对象构造函数
Java 中的所有构造函数都必须调用 Object
构造函数。这是通过调用 super()
完成的。这必须是构造函数中的第一行。这样做的原因是,在执行任何其他初始化之前,实际上可以在堆上创建对象。
如果你没有在构造函数中指定对 super()
的调用,编译器会为你输入。
所以这三个例子在功能上是相同的
显式调用 super()
构造函数
public class MyClass {
public MyClass() {
super();
}
}
隐式调用 super()
构造函数
public class MyClass {
public MyClass() {
// empty
}
}
使用隐式构造函数
public class MyClass {
}
那么 Constructor-Chaining 呢?
可以将其他构造函数作为构造函数的第一条指令调用。由于对超级构造函数的显式调用和对另一个构造函数的调用都必须是第一个指令,因此它们是互斥的。
public class MyClass {
public MyClass(int size) {
doSomethingWith(size);
}
public MyClass(Collection<?> initialValues) {
this(initialValues.size());
addInitialValues(initialValues);
}
}
调用 new MyClass(Arrays.asList("a", "b", "c"))
将使用 List-argument 调用第二个构造函数,List-argument 将依次委托给第一个构造函数(它将隐式委托给 super()
),然后使用列表的第二个大小调用 addInitialValues(int size)
。这用于减少代码重复,其中多个构造函数需要执行相同的工作。
如何调用特定的构造函数?
鉴于上面的例子,可以调用 new MyClass("argument")
或 new MyClass("argument", 0)
。换句话说,就像方法重载一样 ,你只需使用所选构造函数所必需的参数调用构造函数。
Object 类构造函数会发生什么?
没有比在具有默认空构造函数的子类中发生的更多(减去对 super()
的调用)。
可以显式定义默认的空构造函数,但如果没有,只要没有定义其他构造函数,编译器就会将它放入其中。
然后如何从 Object 中的构造函数创建一个 Object?
对象的实际创建归结为 JVM。Java 中的每个构造函数都显示为一个名为 <init>
的特殊方法,它负责实例初始化。这个 <init>
方法由编译器提供,因为 <init>
不是 Java 中的有效标识符,所以它不能直接在该语言中使用。
JVM 如何调用此
<init>
方法?
JVM 将使用 invokespecial
指令调用 <init>
方法,并且只能在未初始化的类实例上调用。
有关更多信息,请查看 JVM 规范和 Java 语言规范:
- 特殊方法(JVM) - JVMS - 2.9
- 构造函数 - JLS - 8.8