Search code examples
javaconstructorfinaljls

Initialization order of final fields


Consider these two classes:

public abstract class Bar {
    protected Bar() {
        System.out.println(getValue());
    }

    protected abstract int getValue();
}

public class Foo extends Bar {
    private final int i = 20;

    public Foo() {
    }

    @Override
    protected int getValue() {
        return i;
    }

    public static void main(String[] args) {
        new Foo();
    }
}

If I execute Foo, the output is 20.

If I make the field non-final, or if I initialize it in the Foo constructor, the output is 0.

My question is: what is the initialization order in case of final fields and where is this behavior described in the JLS?

I expected to find some exceptional rule about final fields here, but unless I miss something, there isn't.

Note that I know I should never call an overridable method from a constructor. That's not the point of the question.


Solution

  • Your final int i member variable is a constant variable: 4.12.4. final Variables

    A variable of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28), is called a constant variable.

    This has consequences for the order in which things are initialized, as described in 12.4.2. Detailed Initialization Procedure.