You see the effects of three things:
By default, calls to the super constructor and
Instance initializers regarding supercalls and
How overridden methods work
Constructor Sub1 really :
Sub1(){ super(); // <== Default super() call, inserted by the compiler three=(int) Math.PI; // <== Instance initializers are really inserted // into constructors by the compiler super.printThree(); }
(Surprisingly, I know, but it's true. Use javap -c YourClass to search. :-))
It seems like this is so that the superclass must be able to initialize its part of the object before the subclass can initialize its part of the object. Thus, you get such an intertwined effect.
And given that what Sub1 really looks like allows you to get through it:
The JVM instantiates and sets all instance fields to defaults (all bits are off). So, at this moment there is a three field and has a value of 0 .
JVM calls Sub1 .
Sub1 immediately calls super() ( Super1 ), which ...
... calls printThree . Since printThree overridden, although the call to it is in the code for Super1 , it calls the overridden method (the one that is in Sub1 ). This is part of how Java implements polymorphism. Since three instance initializer is not running yet, three contains 0 , and that gets the result.
Super1 returns.
Back in Sub1 , the instance initializer code for three , which was inserted (moved, really) by the compiler, and gives three new value.
Sub1 calls printThree . Since three instance initializer code is now running, printThree prints 3 .
As for this instance initializer code that moves to the constructor, you might be wondering: what if I have multiple constructors? What code has the code moved to? The answer is that the compiler duplicates the code in each constructor. (You can also see this in javap -c .) (If you have a really complex instance initializer, I would not be surprised if the compiler turned it into a method, but I did not look.)
This is a little clearer if you are doing something really naughty and calling the method during your init instance: ( live copy )
class Super { public static void main (String[] args) { new Sub(); } Super() { System.out.println("Super constructor"); this.printThree(); } protected void printThree() { System.out.println("Super printThree"); } } class Sub extends Super { int three = this.initThree(); Sub() { this.printThree(); } private int initThree() { System.out.println("Sub initThree"); return 3; } protected void printThree() { System.out.println("Sub printThree: " + this.three); } }
Output:
Super constructor
Sub printThree: 0
Sub initThree
Sub printThree: 3
Notice where "Sub initThree" appeared in this sequence.
source share