javastaticclassloaderoperator-precedencestatic-initializer

Are static initialisers necessarily executed in hierarchical order?


Let's say I have a class

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

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

and I create a subclass

class B extends A{
    long y;

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

If I now write some code to check the static initialisers:

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

I know both entries must be in tmap because A must get loaded, eventually, for B's super call at the very latest.

But if I'm reading When does static class initialization happen? correctly, I cannot assume that the Hello value is put into the map first all the times because tmap is final.

So if ordering were important (say if I knew there's a chance some values may be updated/overwritten further down the hierachy), do I need to remove the final modifier?

Or is there something else already enforcing "proper" static initialiser ordering?


Solution

  • Static initialization is always done for the super class before the child is initialized, if you have multiple static initializer blocks, they are executed in order. (Edit: Thanks to Holger for pointing out that this does not have to be directly when the class is loaded).

    In your example, B extends A, and the classloader therefore has to load A before B. Thus, the static initializer of A ist executed first.

    This has nothing to do with the final modifier. What the other thread probably refers to is that if the compiler can perform constant folding( https://www.javaworld.com/article/2076060/build-ci-sdlc/compiler-optimizations.html), the class from which the constant is taken will not be static initialized (as the reference is replaced at compile time).