Search code examples
javastaticinitialization

Why does java not initialise static nested class fields at the same time as static outter fields?


Java initializes outer class static field when that class is interacted with, but does not initialize nested static class field.

So I have read the nested class documentation: https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html and I think it comes down to this line here:

In effect, a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience.

If my understanding is correct that means that java views my two classes below as separate entities;

public class OutterClass {

    private static final OutterClass outterField = new OutterClass("outterField");

    private OutterClass(String string) {
        System.out.println(string + " has been initialised");
    }

    private static class InnerClass {
        private static final OutterClass innerField = new OutterClass("innerField");
    }

    public static void foo() {}
}

Meaning that when I interact with the OuterClass by calling the Outer.foo(), java will initialize my static field as it is part of the OuterClass. But since it views the InnerClass as a separate top level class, InnerClass's fields don't get initialized.

1) Is my understanding correct?

2) Has this got anything to do with the JIT compiler or the class loader? Is the InnerClass loaded when the OuterClass is loaded?

Thanks


Solution

  • 1) Is my understanding correct?

    Basically yes. Consider what happens with your static member outerField :

    public class OutterClass {
    
        private static final OutterClass outterField = new OutterClass("outterField");
    

    Theoretically, it's possible that the JVM could create that static final object when the program starts running, or when the class is loaded, but it doesn't. Instead, it'll only initialise it when needed - basically :

    • Instance of class is created, or
    • One of the Class's static fields or methods is accessed

    (see https://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1 )

    So also with the static inner class. As you say, the JVM regards it as a top level inner class, so will only initialise its members when it also is needed.

    2) Has this got anything to do with the JIT compiler or the class loader?

    No and no. Initialisation of static members does not take place at class load time, but later (as we said, when the class is accessed). This is not a matter of compiler optimisation, but explicitly specified behaviour. After all, when you load a possibly-large class library, you would not want your JVM to consume memory or time initialising all the static members of classes that your program never touches; only-on-demand is a much better approach.

    Is the InnerClass loaded when the OuterClass is loaded?

    Yes (but not initialised then)