Java初始化顺序问题,静态与实例字段
下面的程序打印:Java初始化顺序问题,静态与实例字段,java,Java,下面的程序打印: my name is:null my name is:null Someclass static init AFAIK当类第一次加载时,静态块和字段总是首先初始化,实例块和字段总是第二次初始化。因此,变量“objectName1”和“objectName2”应该首先初始化,实例变量“list”应该第二次初始化……但是输出显然与这一理论相矛盾。。。有人能解释程序的行为吗(顺便说一句,我不是在寻找对设计本身的批评) import java.util.ArrayList; 导入
my name is:null
my name is:null
Someclass static init
AFAIK当类第一次加载时,静态块和字段总是首先初始化,实例块和字段总是第二次初始化。因此,变量“objectName1”和“objectName2”应该首先初始化,实例变量“list”应该第二次初始化……但是输出显然与这一理论相矛盾。。。有人能解释程序的行为吗(顺便说一句,我不是在寻找对设计本身的批评)
import java.util.ArrayList;
导入java.util.List;
公共类Main2{
公共静态void main(字符串[]args){
getInstance();
}
}
上课{
私有静态最终SomeClass实例=新建SomeClass();
公共静态SomeClass getInstance(){
返回实例;
}
静止的{
System.out.println(“Someclass静态初始化”);
}
私有静态字符串objectName1=“test1”;
私有静态字符串objectName2=“test2”;
@抑制警告(“串行”)
私人名单=
新的ArrayList(){{
添加(新的SomeObject(objectName1));
添加(新的SomeObject(objectName2));
}};
}
类对象{
字符串名;
SomeObject(字符串名称){
this.name=名称;
System.out.println(“我的名字是:“+name”);
}
}
静态块是按顺序初始化的(因此您可以在下面的块中依赖上面的块)。通过创建SomeClass
的实例作为SomeClass
中的第一个静态初始值设定项,可以在静态初始化阶段强制实例初始化
因此,代码执行的逻辑顺序是:
- 加载类
,所有静态字段初始默认值(SomeClass
,0
,等等)null
- 开始静态初始化
- 第一个静态init创建
SomeClass的实例
- 使用静态字段的当前值开始
实例的实例初始化(因此SomeClass
和objectName1
为objectName2
)null
- 加载
类,所有静态字段最初都是默认值(您没有任何字段)SomeObject
- Do
static inits(您没有任何)SomeObject
- 使用传入的
值创建null
的实例SomeObject
- 继续
的静态初始化,设置SomeClass
和objectName1
objectName2
要使这项工作如您所料,只需将
objectName1
和objectName2
的init放在instance
的init之上,首先执行的可能是instance
变量的静态初始值设定项。这会导致使用(未初始化的)objectName1
和objectName2
变量初始化列表。之后,它继续初始化objectName1
和objectName2
如果将
instance
的声明移动到SomeClass
的末尾,它可能会达到您的预期效果。建议移动此行:
private static final SomeClass instance = new SomeClass();
在此之后:
private static String objectName1 ="test1";
private static String objectName2 ="test2";
应该可以解决这个问题。乍看之下,我对自己的行为感到非常惊讶,但仔细想想,解释一下就很简单了:
private static final SomeClass instance = new SomeClass();
是SomeClass
静态初始化的一部分。当您在初始化完成之前创建实例时,该类尚未完全初始化。替换System.out.println(…)时代码>类似于新异常().printStackTrace()代码>您得到了这个(注意,我将所有类作为静态嵌套类放入Main)
private static final SomeClass instance = new SomeClass();
at Main$SomeObject.<init>(Main.java:37) // new Exception().printStackTrace();
at Main$SomeClass$1.<init>(Main.java:26) // add(new SomeObject(...))
at Main$SomeClass.<init>(Main.java:23) // list = new ArrayList()
at Main$SomeClass.<clinit>(Main.java:10) // instance = new SomeClass()
at Main.main(Main.java:6) // SomeClass.getInstance();
class enum SomeClass {
instance;
// snip
}