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
    SomeObject
    static inits(您没有任何)
  • 使用传入的
    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
}