以下代码打印null
一次。
class MyClass {
private static MyClass myClass = new MyClass();
private static final Object obj = new Object();
public MyClass() {
System.out.println(obj);
}
public static void main(String[] args) {}
}
为什么在构造函数运行之前没有初始化静态对象?
更新
我只是在没有注意的情况下复制了这个示例程序,我以为我们正在讨论2个Object字段,现在我看到第一个是MyClass字段..:/
答案 0 :(得分:37)
因为静态按照源代码中给出的顺序进行初始化。
检查出来:
class MyClass {
private static MyClass myClass = new MyClass();
private static MyClass myClass2 = new MyClass();
public MyClass() {
System.out.println(myClass);
System.out.println(myClass2);
}
}
那将打印:
null
null
myClassObject
null
修改强>
好的,让我们更清楚地说明这一点。
这是清楚的吗?
编辑2
正如Varman所指出的,在初始化时,对它自身的引用将为null。如果你考虑一下,这是有道理的。
答案 1 :(得分:22)
让我们尝试一种不同的方式来解释这个......
这是JVM首次引用类MyClass
时所经历的序列。
static { ... }
块。myClass
静态变量初始化为MyClass
的新实例。MyClass
已经加载(字节码)并且正在初始化,因此它会跳过初始化。obj
的{{1}}的值(因为它不是堆和构造函数初始化变量的一部分)。null
设置为obj
的新实例。Object
不是obj
,而是对null
实例的引用。请记住,Java指定为Object
变量赋值一次。并不是保证在代码引用它时为其分配值,除非您确保代码在分配后引用它。
这不是错误。这是在自己的初始化期间处理类使用的定义方法。如果不是这样,那么JVM将进入无限循环。请参阅步骤#3.3(如果JVM没有跳过正在初始化过程中的类的初始化,它将继续初始化它 - 无限循环)。
请注意,这一切都发生在首次引用该类的同一个线程上。其次,JVM保证在允许任何其他线程使用此类之前完成初始化。
答案 2 :(得分:19)
这是因为Java按照声明的顺序执行静态部分。在您的情况下,序列是
当执行#1时,obj仍未初始化,因此它打印为null。尝试以下操作,您将看到不同之处:
class MyClass {
private static final Object obj = new Object();
private static MyClass myClass = new MyClass();
public MyClass() {
System.out.println(obj); // will print null once
}
}
一般来说,最好一起避免这种结构。如果您正在尝试创建单例,那么代码片段应该是这样的:
class MyClass {
private static final MyClass myClass = new MyClass();
private Object obj = new Object();
private MyClass() {
System.out.println(obj); // will print null once
}
}
答案 3 :(得分:0)
这是因为静态字段按照它们定义的相同顺序初始化。
答案 4 :(得分:0)
@Pyrolistical
因为第一个静态字段的初始化myclass没有完全构造...我得到的结果是
空 空值 testInitialize.MyObject@70f9f9d8 空