奇怪的 Java 行为,带有静态和最终限定符

2022-08-31 13:06:33

在我们的团队中,我们发现了一些奇怪的行为,我们同时使用了限定符和限定符。这是我们的测试类:staticfinal

public class Test {

    public static final Test me = new Test();
    public static final Integer I = 4;
    public static final String S = "abc";

    public Test() {
        System.out.println(I);
        System.out.println(S);
    }

    public static Test getInstance() { return me; }

    public static void main(String[] args) {
        Test.getInstance();
    }
} 

当我们运行该方法时,我们得到的结果如下:main

null
abc

如果它两次都写入值,我会理解,因为静态类成员的代码是从上到下执行的。null

谁能解释为什么会发生这种行为?


答案 1

以下是运行程序时执行的步骤:

  1. 在可以运行之前,必须通过按出现顺序运行静态初始值设定项来初始化类。mainTest
  2. 要初始化字段,请开始执行 。menew Test()
  3. 打印 的值。由于字段类型是 ,看起来像编译时常量的东西就变成了计算值()。此字段的初始值设定项尚未运行,正在打印初始值。IInteger4Integer.valueOf(4)null
  4. 打印 的值。由于它是使用编译时常量初始化的,因此此值将烘焙到引用站点中,打印 。Sabc
  5. new Test()完成,现在是执行的初始值设定项。I

教训:如果您依赖于预先初始化的静态单例,请将单例声明作为最后一个静态字段声明,或者求助于在所有其他静态声明之后出现的静态初始值设定项块。这将使类看起来完全初始化为单例的构造代码。


答案 2

S是一个编译时常量,遵循 JLS 15.28 的规则。因此,代码中出现的任何 都替换为编译时已知的值。S

如果将 的类型更改为 ,您也会看到相同的类型。Iint


推荐