当尝试使用对同一个封闭类对象的引用初始化静态字段时,我试图理解初始化顺序的行为。
public class Test {
static final Test t=new Test();
static int a=5;
Test(){
System.out.println("a="+a);
}
public static void main(String[] args) {
new Test();
}
}
以上代码的输出是:
a=0
a=5
如果我将变量a
修改为除static
以外的任何其他内容:
static final a=5;
a=5;
final a=5;
输出结果为:
a=5
a=5
为什么会出现这种情况?
请注意,即使两个a=5 & a=5
都声明为t & a
,static final
输出也是t
,a
}>
答案 0 :(得分:3)
静态最终成员在其他静态成员之前初始化。
非最终静态成员按外观顺序初始化
因此,在您的第一个案例中:
static Test t=new Test();
static int a=5;
在a
初始化之前首先调用构造函数,因此显示a=0
。
在第二种情况下,static final a
在t
之前初始化,因此在创建a=5
的第一个实例时会显示Test
。如果a
不是静态的,则会在执行构造函数之前对其进行初始化,因此会再次显示a=5
。
关于你问题的编辑。
查看12.4.2 of the JLS部分:
- 然后,初始化最终的类变量和接口的字段,其值为编译时常量表达式(§8.3.2.1,§9.3.1,§13.4.9,§15.28)。
醇>...
- 接下来,按文本顺序执行类的类变量初始值设定项和静态初始值设定项,或接口的字段初始值设定项,就好像它们是单个块一样。
醇>
您会看到最终的类变量(即static final)仅在其值为编译时constant expressions之前在其余静态变量之前初始化。 5
是一个常量表达式。 new Test()
不是。因此a
会在t
之前初始化,即使两者都是静态最终结果。
答案 1 :(得分:1)
当类加载器加载类时,静态变量被初始化。因此,当第一行“静态测试t =新测试();”执行时,int“a”的值尚未初始化,因此它显示为0.但是其他3种情况(即删除静态,添加最终或没有任何修饰符)在创建Test类的Object时初始化会发生什么,这发生在第一行,因此它显示值“5”。
答案 2 :(得分:1)
Java Language specification是了解初始化顺序的最佳来源。根据您的方案中的情况,static final
字段在任何类级别变量初始化之前初始化。删除最终结果后,初始化被推迟。如果你改变了
static Test t=new Test();
static int a=5;
到
static int a=5;
static Test t=new Test();
它也会打印
a = 5
a = 5
因为初始化顺序。
答案 3 :(得分:0)
static final a=5
它是final
所以它首先在其他静态成员或方法之前初始化。
在第一个方案main()
方法首先执行,并将a
初始化为其默认值0
。