Java初始化顺序问题,静态与实例字段
下面的程序打印:
my name is:null
my name is:null
Someclass static init
AFAIK当类第一次加载时,静态块和字段总是首先初始化,实例块和字段总是第二次初始化。因此,应首先初始化变量“objectName1”和“objectName2”,然后初始化实例变量“list”。。。但这显然与这一理论相矛盾。。。有人能解释程序的行为吗(顺便说一句,我不是在寻找对设计本身的批评)
import java.util.ArrayList;
import java.util.List;
public class Main2{
public static void main (String[] args){
SomeClass.getInstance();
}
}
class SomeClass {
private static final SomeClass instance = new SomeClass();
public static SomeClass getInstance(){
return instance;
}
static {
System.out.println ("Someclass static init");
}
private static String objectName1 ="test1";
private static String objectName2 ="test2";
@SuppressWarnings("serial")
private List<SomeObject> list=
new ArrayList<SomeObject> () { {
add (new SomeObject(objectName1));
add (new SomeObject(objectName2));
}};
}
class SomeObject {
String name;
SomeObject (String name){
this.name = name;
System.out.println ("my name is:" +name);
}
}
# 1 楼答案
静态块按照的顺序初始化(因此您可以在下面的块中依赖上面的块)。通过创建
SomeClass
的实例作为SomeClass
中的第一个静态初始值设定项,您在静态初始化阶段强制执行实例初始化因此,代码执行的逻辑顺序是:
SomeClass
,所有静态字段最初都是默认值(0
,null
,等等)SomeClass
的实例SomeClass
实例的实例初始化(因此objectName1
和objectName2
是null
)SomeObject
类,所有静态字段最初都是默认的(您没有任何静态字段)SomeObject
静态初始化(你没有)null
值创建SomeObject
的实例SomeClass
的静态初始化,设置objectName1
和objectName2
要使这项工作如您所料,只需将
objectName1
和objectName2
的init置于instance
的init之上# 2 楼答案
首先执行的可能是
instance
变量的静态初始值设定项。这会导致使用(未初始化的)objectName1
和objectName2
变量初始化列表。之后,它继续初始化objectName1
和objectName2
如果你把
instance
的声明移到SomeClass
的末尾,它可能会达到你所期望的效果# 3 楼答案
乍一看,我对自己的行为感到非常惊讶,但再想想,要解释这一点很简单:
是
SomeClass
静态初始化的一部分。在初始化完成之前创建实例时,该类尚未完全初始化。当您用类似new Exception().printStackTrace();
的东西替换System.out.println(...);
时,您会得到这样的结果(注意,我将所有类作为静态嵌套类放入Main)如您所见,执行仍然在
Main$SomeClass.<clinit>
(类初始化)中,因此SomeClass没有完全初始化附带说明:实现单例模式的最佳方法是完全避免它。第二种最有可能的方法是使用
enum
(至少是Josh Bloch批准的)# 4 楼答案
正如建议移动这条线:
在这些之后:
应该可以解决这个问题