这可能听起来很基本.但我是Java的新手.到目前为止,我已经投入了很少的初始学习时间,我一直对新对象声明的语法冗余感到困惑:
TypeName a = new TypeName();
Run Code Online (Sandbox Code Playgroud)
特别是,
String s = new String("abc");
Character c = new Character("A");
Run Code Online (Sandbox Code Playgroud)
世界上为什么会有人想要输入关键字TypeName
(例如String
,Character
等...)的两倍?我知道有简短的手:
String s = "abc";
char c = "A";
Run Code Online (Sandbox Code Playgroud)
但这些是例外而不是规则.那么有人可以开导我吗?谢谢.
Jus*_*ner 19
因为有时你想做的事情如下:
// Explicitly force my object to be null
String s = null;
Run Code Online (Sandbox Code Playgroud)
要么
// Cast a child class to its parent
MyParentClass mpc = new IneritedClassFromParent();
Run Code Online (Sandbox Code Playgroud)
要么
// Store and access a concrete implementation using its interface
ISomeInterface isi = new ConcreteInterfaceImplementation();
Run Code Online (Sandbox Code Playgroud)
换句话说,仅仅因为您声明要存储的类型并不总是意味着您希望使用该类的新实例初始化它.
在使用接口时,您可能希望在使用继承或接口实现时使用子类的新实例.
或者有时您可能希望最初明确强制某些内容为null并稍后填充它.
使用此语法,您可以轻松创建类型的对象X
并将其分配给类型的变量Y
:
List<String> myList = new ArrayList<String>();
Run Code Online (Sandbox Code Playgroud)
为什么在世界上有人想要两次输入关键字TypeName(例如String,Character等)?
因为你做了两件事:
这两种类型不一定相同,例如
Map m = new HashMap();
Run Code Online (Sandbox Code Playgroud)
您可能习惯于使用"动态类型化"的语言,例如PHP,其中变量没有类型.使用Java的静态类型声明所获得的优势是编译器捕获了许多编程错误(即使在现代IDE中,您在键入时也是如此).例如,如果你犯了一个简单的错误:
m.siez();
Run Code Online (Sandbox Code Playgroud)
编译器会立即提醒您程序出现问题 - 它只能因为它知道声明的类型Map
没有方法而这样做siez()
.
一些现代的静态类型语言(如C#和Scala)使用类型推断来为您提供"两全其美",您可以省略类型声明,编译器将假定它与您分配给它的对象的类型相同.但是,这些语言总是允许显式类型声明,因为类型推断并不总是可行的或者是desirables(例如在上面的示例中,变量应该使用接口而不是具体类).
这一点也不多余。使用变量有两个步骤:
声明:这一步告诉VM变量的静态足迹是什么。例如:Object a;
只有类中声明的封装可见Object
,而类和所有继承的父类Integer b;
中声明的所有封装都可见。这是静态部分。Integer
Object
实例化:这一步告诉虚拟机变量的动态足迹是什么。例如:List<String> c = new LinkedList<String>();
,那么c.put("foo");
将使用LinkedList
该put()
方法的实现,即使可见的是List::put()
。有时,您将需要这种声明/实例化,但需要重写以访问静态足迹不可见的非常特定的方法。例如,让我们考虑一个声明为 的方法,public void method1(Object obj)
并且您知道该obj
实例实际上是一个Integer
,因此您将通过将对象强制转换到其中来专门使用动态足迹:int value = ((Integer) obj).intValue();
现在,至于部分String a = "A";
。为了简单起见,Java 已经提供了“原始”类的简写形式。更具体地说,从 Java 1.5 开始,您可以执行以下操作:
Integer n1 = 1;
Integer n2 = new Integer(1); // same thing
int n3 = n2;
Run Code Online (Sandbox Code Playgroud)
一切正常。但有什么区别呢?考虑这段代码:
String a = new String("A");
String b = new String("A");
String c = "A";
String d = "A";
System.out.println("a:" + a.hashCode() + " = b:" + b.hashCode() + " == " + (a == b));
System.out.println("b:" + b.hashCode() + " = c:" + c.hashCode() + " == " + (b == c));
System.out.println("c:" + c.hashCode() + " = d:" + d.hashCode() + " == " + (c == d));
Run Code Online (Sandbox Code Playgroud)
将输出
a:65 = b:65 == false
b:65 = c:65 == false
c:65 = d:65 == true
Run Code Online (Sandbox Code Playgroud)
为什么?因为 JVM 尝试尽可能多地重用内存,并且由于a
和b
正在创建 a 的新实例String
,所以它们不共享相同的内存空间。但是,c
和d
正在使用常量字符串值(这是编译器优化),因此指向完全相同的String
对象。