构造函数代码在Java中运行之前是否已初始化字段?
任何人都可以解释下面的程序的输出? 我认为构造函数是在实例variables之前初始化的。 所以我期待的输出是“XZYY”。
class X { Y b = new Y(); X() { System.out.print("X"); } } class Y { Y() { System.out.print("Y"); } } public class Z extends X { Y y = new Y(); Z() { System.out.print("Z"); } public static void main(String[] args) { new Z(); } }
正确的初始化顺序是:
- 静态variables初始化程序和静态初始化块,如果该类尚未初始化,则按文本顺序排列。
- 在构造函数中的super()调用,无论是显式的还是隐式的。
- 实例variables初始化程序和实例初始化块,按照文本顺序。
- super()之后剩余的构造函数体。
请参阅Java虚拟机规范的§2.17.5-6部分。
如果您查看类文件的反编译版本
class X { Y b; X() { b = new Y(); System.out.print("X"); } } class Y { Y() { System.out.print("Y"); } } public class Z extends X { Y y; Z() { y = new Y(); System.out.print("Z"); } public static void main(String args[]) { new Z(); } }
你可以发现实例variablesy
在构造函数内部移动,所以执行顺序如下
- 调用
Z
的构造函数 - 它触发
X
的默认构造函数 -
X
构造函数new Y()
第一行被调用。 - 打印Y
- 打印X
- 调用构造函数Z
new Y()
的第一行 - 打印
Y
- 打印Z
所有的实例variables都使用构造函数语句进行初始化。
初始化的顺序如下所示:
- 静态variables和初始化块按照它们出现的顺序
- 在构造函数体中调用
super()
- 实例variables和初始化块,按照它们出现的顺序
- 其余的构造函数体
从Java虚拟机规范中的§12.5节开始 。
初始化序列在JLS 12.5中指定:
首先,内存分配给新的对象
2.然后,对象中的所有实例variables(包括在这个类及其所有超类中定义的variables)被初始化为它们的默认值
最后,调用构造函数。