Java static final 字段初始化顺序

Java static final field initialization order

我试图理解当静态字段通过引用相同的封闭 class 对象来初始化时初始化顺序的行为。

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

为什么会这样?

请注意,即使两个 t & a 都声明为 static final,输出也是 a=5 & a=5,在这种情况下 ta[= 的声明之前22=]

static final a=5 它是 final 所以它首先初始化,在其他静态成员或方法之前。

在第一种情况下 main() 方法首先被执行,并将 a 初始化为其默认值 0

静态最终成员在其他静态成员之前初始化。

非final静态成员按出现顺序初始化

因此,在您的第一种情况下:

    static Test t=new Test();
    static int a=5;

在初始化a之前首先调用构造函数,所以显示a=0

第二种情况,static final a先于t初始化,所以Test的第一个实例创建时显示a=5。当 a 不是静态时,它在构造函数执行之前被初始化,因此再次显示 a=5

关于您问题中的修改。

查看第 12.4.2 of the JLS 部分:

  1. Then, initialize the final class variables and fields of interfaces whose values are compile-time constant expressions (§8.3.2.1, §9.3.1, §13.4.9, §15.28).

...

  1. Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.

你看到最终 class 变量(即静态最终)只有在它们的值是编译时 constant expressions 时才会在其余静态变量之前初始化。 5 是常量表达式。 new Test() 不是。因此 at 之前初始化,即使两者都是静态最终的。

静态变量在 class 被 class 加载程序加载时初始化。所以当第一行“static Test t=new Test();”被执行时,int “a” 的值尚未初始化,因此它显示为 0。但是其他 3 种情况(即删除 static,添加 final 或没有任何修饰符)发生的事情 a 在对象创建时被初始化测试 class,这发生在第一行,因此它显示值“5”。

Java Language specification 是了解初始化顺序的最佳来源。根据您的场景, static final 字段在任何 class 级别变量初始化之前被初始化。当您删除 final 时,初始化被推迟。如果改了也要注意

static Test t=new Test();
static int a=5;

  static int a=5;
  static Test t=new Test();

它也会打印

 a = 5
 a = 5

因为初始化顺序。