I must have spent over an hour trying to figure out the reason for some unexpected behavior. I ended up realizing that a field wasn't being set as I'd expect. Before shrugging and moving on, I'd like to understand why this works like this.
In running the example below, I'd expect the output to be true, but it's false. Other tests show that I always get whatever that type default value is.
public class ClassOne {
public ClassOne(){
fireMethod();
}
protected void fireMethod(){
}
}
public class ClassTwo extends ClassOne {
boolean bool = true;
public ClassTwo() {
super();
}
@Override
protected void fireMethod(){
System.out.println("bool="+bool);
}
public static void main(String[] args) {
new ClassTwo();
}
}
output:
bool=false
boolean bool = true;
public ClassTwo() {
super();
}
is identical to
boolean bool;
public ClassTwo() {
super();
bool = true;
}
The compiler automatically moves the fields initializations within the constructor (just after the super constructor call, implicitly or explicitly).
Since a boolean field default value is false
, when super()
is called (and thus ClassOne()
and fireMethod()
), bool
hasn't been set to true
yet.
Fun fact: the following constructor
public ClassTwo() {
super();
fireMethod();
}
will be understood as
public ClassTwo() {
super();
bool = true;
fireMethod();
}
by the JVM, and the output will thus be
bool=false
bool=true
The superclass constructor is called before the subclass constructor. And in Java, before a constructor is run, all instance members have their default value (false, 0, null). So when super()
is called, bool
is still false (default value for booleans).
More generally, calling an overridable method from a constructor (in ClassOne) is a bad idea for the reason you just discovered: you might end up working on an object that has not been fully initialised yet.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With