For the line A a = new B();
the output is null 2 B 2
, because the instance fields in your class are not initialized until the implicit super()
is finished running.
In this case since class B
is extending the class A
the B()
constructor will implicitly call the super class no-arg constructor A()
through super()
, where the foo()
method is called.
public A() { <---
foo(); //overriden version in class B is called |
} |
|
public B() { |
// Static fields are already initialized |
// Instance fields are not yet initialized |
// Here super() is called implicitly which calls A() ---
// Instance fields are now initialized to respective values
foo();
}
The overriden foo()
of class B
is called and as the foo()
is overriden in class B
, now since the super()
is not yet finished the instance fields of class B
is not initialized and is null
. So you see the first null 2
.
Then when the control comes out of super()
the instance initializers are run for B
and then foo()
of class B
is called at which point the instance fields of class B
is initialized to the value B
, so you see B 2
printed.
You don't see any issue for the static fields as because they don't depend on the super()
call to finish, they are initialized when the class is loaded, so you see the value of i
always initialized and printed instead of null
.
Same is the case for the line B b = new B();
.
An important thing to note is that you have redefined the str
instance field in class B
, so when the overriden foo()
is invoked it will actually refer to the instance field of the class B
rather than the field of class A
.
Consider this code, where I removed the str
field from class B
:
class A {
protected String str = "A";
public static int i = 1;
public A() {
foo();
}
public void foo() {
// TODO Auto-generated method stub
System.out.println(str + " " + i);
}
}
class B extends A {
public static int i = 2;
public B() {
foo();
}
public void foo() {
// TODO Auto-generated method stub
System.out.println(str + " " + i);
}
}
This will print the output below when you re-run your program:
A 2
A 2
A 2
A 2
This is happening because the super()
of B
is calling the constructor A()
which in turn is calling the Object()
constructor through its own super()
. Once the super()
is done in A()
the instance members of B
inherited from A
are all initialised. Now the overriden foo()
will print out the initialised value of str
inherited from A
.