最终字段初始化顺序

Ser*_*aev 29 java jls

下面是一些在尚未初始化的类上调用静态方法Af()的代码.有人可以用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 B {
    static {
        A.f();
    }
}

public class App
{
    public static void main( String[] args )
    {
        A.f();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

1
null
1
2
Run Code Online (Sandbox Code Playgroud)

xeh*_*puk 29

A.f()App.main()触发器初始化类A.

初始化所有常量变量.唯一的常量变量是S1,现在是1.

然后,以文本顺序初始化其他静态字段.b是第一个字段,它触发类的初始化,B然后调用A.f().S2只是null因为它尚未初始化.初始化b现已完成.最后但并非最不重要的S2是,初始化为Integer对象2.

S2不是常量变量,因为它不是基本类型int而是引用类型Integer.S2 = 2;是一种自动拳击速记S2 = Integer.valueOf(2);.

如果字段声明中的声明符具有变量初始值设定项,则声明符具有声明变量的赋值(第15.26节)的语义.

[...]

请注意,static作为常量变量的static字段(第4.12.4节)在其他字段(第12.4.2节)之前初始化.这也适用于接口(第9.3.1节).即使是狡猾的程序,也永远不会观察到这些字段具有默认的初始值(§4.12.5).

8.3.2.场初始化

常量变量final原始类型或类型的变量String,其与一个常量表达式(§15.28)初始化.变量是否是常量变量可能对类初始化(第12.4.1节),二进制兼容性(第13.1节,第13.4.9节)和明确赋值(第16节(定义赋值))有影响.

4.12.4.final变量

常量表达式是表示原语类型的值的表达式或String不突然完成并且使用仅由以下内容:

  • 原始类型的文字和类型的文字 String

[...]

15.28.常数表达式

对于每个类或接口C,都有一个唯一的初始化锁LC.从C到C的映射由LCJava虚拟机实现决定.初始化C的过程如下:

[...]

  1. 否则,记录Class当前线程正在进行C对象初始化并释放的事实LC.

    然后,初始化staticC 的字段,它们是常量变量(§4.12.4,§8.3.2,§9.3.1).

[...]

  1. 接下来,按文本顺序执行类的类变量初始值设定项和类的静态初始值设定项,或接口的字段初始值设定项,就好像它们是单个块一样.

12.4.2.详细的初始化程序

程序中的每个变量在使用其值之前必须具有值:

  • 每个类变量,实例变量或数组组件在创建时都会使用默认值进行初始化(§15.9,§15.10.2):

    [...]

    • 对于所有引用类型(§4.3),默认值为null.

4.12.5.变量的初始值

  • @SpaceTrucker你的问题是为什么在`b`之前初始化`S1`?在所述部分的步骤6中初始化"S1". (2认同)