Why is my field not being initialized with the value I gave it
I have the following classes:
public abstract class AClass {
public AClass() {
aMethod();
}
abstract protected void aMethod();
}
public class SubClass extends AClass {
private int x = 5;
private static final int y = 6;
@Override
protected void aMethod() {
System.out.println("x: " + x + " | y: " + y);
}
}
public class Main {
public static void main(String[] args) {
new SubClass();
}
}
Running Main prints the following: x: 0 | y: 6
Why is 0 printed for x?
The wrong behavior is caused by the wrong initialization sequence:
-
new SubClass()
executes the constructorAClass
-
AClass
constructor callsaMethod()
-
aMethod()
showsx
(so far0
) andy
which is6
due to static) -
SubClass
initializes its non-static fields, sox
it becomes5
.
To avoid surprises, never call virtual methods (esp. Overriden) in constructors
A static field is initialized as soon as the class is initialized (after loading). Now when you call
new SubClass()
the following events occur.
- The constructor
SubClass
is called as the first statementSubClass
(implicitly)- The constructor is called
SuperClass
. -> you are checking the valuex
here- Execution of the constructor
SuperClass
ends, then the instance-level fields areSubClass
initialized. So,x
will be initialized here.
Initialization order. aMethod()
called before the lineprivate int x = 5
Playing with code examples like this is a great way to find out the order of things. Try adding static and non-static initialization block.
The result is that the superclass's constructor is called before the elements are initialized.
In your case, the following sequence runs:
- Constructor call
SubClass
- immediate constructor call
AClass
- method call
aMethod()
- member initialization
SubClass
This is also the reason why you should not call any overridden methods from the constructor, as the called method can access the state of an object that is not fully initialized.
private static final int y = 6;
The y value is 6 when the constructor calls aMethod () because it is static and initialized when classes are loaded.
private int x = 5;
For now, this initialization is appended to the end of your constructor body. This means that when aMethod is executed, the x variable has a default value ie 0.
The default SubClass constructor would look like
SubClass() {
super();
//All instance initialization are performed here.
}
Because when you instantiated Subclass
, it calls the constructor of its superclass AClass
, and at that point x
it is not set yet why it gets the default 0.