【问题标题】:Java static final field initialization orderJava静态final字段初始化顺序
【发布时间】:2015-01-09 11:20:51
【问题描述】:

当静态字段使用对同一个封闭类对象的引用进行初始化时,我试图了解初始化顺序的行为。

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,在这种情况下,ta 的声明之前,输出也是a=5 & a=5

【问题讨论】:

    标签: java constructor static final static-members


    【解决方案1】:

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

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

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

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

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

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

    关于您问题中的编辑。

    查看12.4.2 of the JLS部分:

    1. 然后,初始化最终类变量和接口字段,其值为编译时常量表达式(§8.3.2.1、§9.3.1、§13.4.9、§15.28)。

    ...

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

    您会看到,final 类变量(即静态 final)只有在其值为编译时 constant expressions 时才会在其余静态变量之前初始化。 5 是一个常量表达式。 new Test() 不是。因此at 之前初始化,即使两者都是静态final。

    【讨论】:

    • 谢谢!但是t也应该在构造函数执行前初始化?它看起来不像是循环依赖吗?当 Java 遇到循环依赖时,是否有任何已定义的行为...?
    • @ernesto t 的初始化会导致创建一个新实例。创建新实例时,将执行构造函数。实例变量初始化语句在构造函数执行之前执行。因此,当a不是静态时,在println语句之前初始化为5。
    • 我更新了问题。即使 t 被声明为 static final (在 a 声明之前),输出也是 a=5 & a-5
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

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

      它也会打印出来

       a = 5
       a = 5
      

      因为初始化顺序。

      【讨论】:

      • 他们在该规范中的什么地方告诉static final 将在其他任何事情之前被初始化?
      • OK,所以第6点表示final变量将在static之前初始化。假设我的班级中有staticfinalstatic final 变量,顺序是什么?
      • 很确定它的静态最终,然后是静态,然后是最终,然后是非最终。每个组内的顺序是从上到下。
      • 具有值的最终变量在任何时候都不能更改,因为它们是编译时常量表达式。所以最终变量,无论是类还是实例级别都在同一级别初始化。对于空白决赛的情况,您的初始化顺序不同(最终变量的初始化可以推迟到初始化程序块的末尾),即首先是静态然后是实例级别。作为常量表达式,您看不到哪个先发生,因为它遵循文本顺序。
      • 我更新了问题。即使t 被声明为static final(在a 声明之前),输出也是a=5 & a-5
      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-02
        • 1970-01-01
        • 2017-05-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多