【问题标题】:Subclass final static initialization prior to superclass class initialization?超类初始化之前的子类最终静态初始化?
【发布时间】:2016-12-30 21:11:07
【问题描述】:

我找不到任何关于此特定案例的特定 SO 帖子,所以我想问一下我认为是/否的问题。

这里是JLS §12.4.2 (Java SE 8),清单 6-7:

  1. [...] 然后, 初始化 C 的静态字段,它们是常量变量 (§4.12.4、§8.3.2、§9.3.1)。
  2. 接下来,如果 C 是类而不是接口,并且它的超类尚未初始化,则令 SC 为其超类 [...] 对于列表中的每个 S [ SC, SI1, ..., SIn ],递归执行整个过程 为 S。如有必要,请先验证并准备 S。 [...]

我的问题:这是否意味着子类的最终静态变量在超类的静态初始化之前被初始化(假设最终静态作为其声明的一部分被初始化)?

【问题讨论】:

    标签: java static initialization final


    【解决方案1】:

    答案是可能。关键部分是constant 字义。

    考虑这段代码

    class Foo {
        public static final int FOO_VALUE = 1000;
    
        static {
            System.err.println("FOO Bar.BAR_VALUE=" + Bar.BAR_VALUE);
        }
    }
    
    class Bar extends Foo {
        public static final int BAR_VALUE = 2000;
    
        static {
            System.err.println("BAR Foo.FOO_VALUE=" + Foo.FOO_VALUE);
        }
    }
    

    这个程序的输出将是

    FOO Bar.BAR_VALUE=2000
    BAR Foo.FOO_VALUE=1000
    

    在这种情况下,Bar 静态最终变量在Foo 静态初始化之前被初始化。 FOO_VALUEBAR_VALUE 都是常量,所以javac 可以内联这个字段。

    但是你可以通过这种方式假装最终变量不是常量来欺骗编译器

    class Foo {
        public static final int FOO_VALUE = Integer.valueOf(1000).intValue();
    
        static {
            System.err.println("FOO " + Bar.BAR_VALUE);
        }
    }
    
    class Bar extends Foo {
        public static final int BAR_VALUE =  Integer.valueOf(2000).intValue();
    
        static {
            System.err.println("BAR " + Foo.FOO_VALUE);
        }
    }
    

    输出将是

    FOO Bar.BAR_VALUE=0
    BAR Foo.FOO_VALUE=1000
    

    所以 Foo 静态初始化器在静态最终 Bar.BAR_VALUE 初始化之前完成。

    【讨论】:

    • 值得注意:一个常量变量是一个基本类型的final变量或String类型的变量,用constant expression初始化。
    猜你喜欢
    • 1970-01-01
    • 2020-04-14
    • 2014-10-06
    • 1970-01-01
    • 2015-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多