This is due to Java dynamic method dispatch.
In your example. when you're instancing with the default constructor a MySub
instance, this implicitly performs a call to the superclass' constructor. Within the superclass' constructor there is a call to myMethod()
which is declared in MySuper
and overridden in MySub
.
Now, even if myMethod
is being called from the superclass' constructor, which could fool us into thinking that the superclass' version of myMethod
is being called, this is not what is actually happening.
The instance that is performing all these calls is still a MySub
instance; therefore the myMethod
implementation that is being invoked by Java is the closest implementation to MySub
, i.e. the myMethod
overridden by MySub
.
So, if in this case the myMethod
version that is being invoked in the superclass' constructor is the one overridden by MySub
, why it's not printing str2
value? This is because, although method calls are dynamically dispatched, fields are statically dispatched. In Java, only methods can override their base class' methods. Child class' fields can only shadow base class' fields (with the same name). So Java already knows at compile time which fields are being used and only at run time which method implementations are being invoked. This means that when you're using a field in a child class, you can be sure that the one you're using is always the one you're referring to.
Getting back to your example, since myMethod
is being invoked from the superclass' constructor, at this point we're still initializing the parent object, the child class' fields have not been initialized yet, they still contain their default values (the default value for references is null). So, in your dynamically dispatched myMethod
we are printing the value of the statically dispatched str2
which is still at null because the child class initialization has not happened yet.