Java 最终字段初始化顺序
下面是一些对尚未初始化的类调用静态方法A.f()的代码。 有人可以用JLS来解释此代码的行为吗Java 最终字段初始化顺序,java,jls,Java,Jls,下面是一些对尚未初始化的类调用静态方法A.f()的代码。 有人可以用JLS来解释此代码的行为吗 class A { final static Object b = new B(); final static int S1 = 1; final static Integer S2 = 2; static void f() { System.out.println(S1); System.out.println(S2); }
class A {
final static Object b = new B();
final static int S1 = 1;
final static Integer S2 = 2;
static void f() {
System.out.println(S1);
System.out.println(S2);
}
}
class B {
static {
A.f();
}
}
public class App
{
public static void main( String[] args )
{
A.f();
}
}
输出:
1
null
1
2
App.main()
中的A.f()
触发类A
的初始化
所有常量变量都已初始化。唯一的常量变量是S1
,现在是1
然后,按照文本顺序初始化其他静态字段b
是第一个字段,它触发类b
的初始化,然后调用A.f()
S2
只是null
,因为它尚未初始化。b
的初始化现已完成。最后但并非最不重要的一点是,S2
被初始化为Integer
对象2
S2
不是常量变量,因为它不是基元类型int
,而是引用类型Integer
<代码>S2=2是S2=Integer.valueOf(2)的自动装箱缩写代码>
如果字段声明中的声明符具有变量初始值设定项,则声明符具有声明变量赋值(§15.26)的语义
[……]
注意,作为常量变量(§4.12.4)的static
字段在其他static
字段(§12.4.2)之前初始化。这也适用于接口(§9.3.1)。即使通过迂回的程序,也不会观察到此类字段具有默认初始值(§4.12.5)
常量变量是原始类型或类型String
的final
变量,用常量表达式初始化(§15.28)。变量是否为常量变量可能涉及到类初始化(§12.4.1)、二进制兼容性(§13.1、§13.4.9)和确定赋值(§16(确定赋值))
常量表达式是表示原语类型的值或字符串的表达式,它不会突然完成,并且仅使用以下内容组成:
- 原语类型的文字和
字符串类型的文字
[……]
对于每个类或接口C,都有一个唯一的初始化锁LC
。从C到LC
的映射由Java虚拟机实现自行决定。初始化C的步骤如下:
[……]
否则,记录当前线程正在初始化C的类
对象,然后释放LC
然后,初始化C的静态
字段,这些字段是常量变量(§4.12.4、§8.3.2、§9.3.1)
[……]
接下来,按照文本顺序执行类的类变量初始值设定项和静态初始值设定项,或者执行接口的字段初始值设定项,就像它们是单个块一样
程序中的每个变量在使用其值之前必须有一个值:
- 每个类变量、实例变量或数组组件在创建时都会使用默认值进行初始化(§15.9、§15.10.2):
[……]
- 对于所有参考类型(§4.3),默认值为
null
这个问题似乎不属于JLS
,但我们已经处理了JVM
在解析
过程之前的链接
阶段,有一个子阶段,包括:
为类或接口创建静态字段并初始化
将这些字段设置为其默认值
还有更多:
静态字段的显式初始值设定项作为
初始化(§5.5),而非准备
而其中包括:
任何一条Java虚拟机指令的执行都是新的
初始化基元类型包括写入它们的初始值。对于引用类型字段,其默认值为null
,因为在子阶段之前,jvm不“知道”哪个类与类的适当符号引用名称关联 我想每个人都同意,令人印象深刻的部分是null
一个,原始对象初始化与非原始对象初始化有一定的优先级,但这与第9步中提到的“文本顺序”有什么关系?@SpaceTrucker是你的问题,为什么S1
在b
之前被初始化<代码>S1
在上述章节的步骤6中初始化。