静态初始化程序是否必须按层次顺序执行?

时间:2018-01-23 14:35:48

标签: java static classloader operator-precedence static-initializer

假设我有一个班级

class A{
    public final static TreeMap<String,String> tmap = new TreeMap<>();
    int x;

    static{
        tmap.put("x:I", "Hello");
    }
}

我创建了一个子类

class B extends A{
    long y;

    static{
        tmap.put("y:J","World");
    }
}

如果我现在编写一些代码来检查静态初始化程序:

class Main{
    public static void main (String[] args){
        B b = new B();
        for(String v : b.tmap.values()){
            System.out.println(v);
        }
    }
}

我知道这两个条目必须在tmap,因为A最终必须加载B的超级电话。

但如果我正确地阅读When does static class initialization happen?,我就不能假设Hello值始终首先放入地图,因为tmap是最终

因此,如果排序很重要(比方说如果我知道某些值可能会在层次结构中进一步更新/覆盖),我是否需要删除final修饰符?

或者还有其他东西已经执行了“正确的”静态初始化程序订购吗?

1 个答案:

答案 0 :(得分:1)

在初始化子级之前,总是对超级类进行静态初始化,如果有多个静态初始化程序块,则按顺序执行它们。 (编辑: 感谢Holger指出在加载类时不必直接使用。)

在你的例子中,B扩展了A,因此类加载器必须在B之前加载A.因此,首先执行A的静态初始化。

这与最终修饰符无关。另一个线程可能引用的是,如果编译器可以执行常量折叠(https://www.javaworld.com/article/2076060/build-ci-sdlc/compiler-optimizations.html),则从中获取常量的类将不会被静态初始化(因为引用在编译时被替换)。