Search code examples
javafinal

Strange Java behaviour with static and final qualifiers


In our team we found some strange behaviour where we used both static and final qualifiers. This is our test class:

public class Test {

    public static final Test me = new Test();
    public static final Integer I = 4;
    public static final String S = "abc";

    public Test() {
        System.out.println(I);
        System.out.println(S);
    }

    public static Test getInstance() { return me; }

    public static void main(String[] args) {
        Test.getInstance();
    }
} 

When we run the main method, we get a result of:

null
abc

I would understand if it wrote null values both times, since the code of static class members is executed from top to bottom.

Can anyone explain why this behaviour is happening?


Solution

  • These are the steps taken when you run your program:

    1. Before main can be run, the Test class must be initialized by running static initializers in order of appearance.
    2. To initialize the me field, start executing new Test().
    3. Print the value of I. Since the field type is Integer, what seems like a compile-time constant 4 becomes a computed value (Integer.valueOf(4)). The initializer of this field has not yet run, printing the initial value null.
    4. Print the value of S. Since it is initialized with a compile-time constant, this value is baked into the referencing site, printing abc.
    5. new Test() completes, now the initializer for I executes.

    Lesson: if you rely on eagerly initialized static singletons, place the singleton declaration as the last static field declaration, or resort to a static initializer block that occurs after all other static declarations. That will make the class appear fully initialized to the singleton's construction code.