There is a code which is given as a task for a junior Java developers. I use Java during five years and this piece of code completely confusing me:
public class Main {
String variable;
public static void main(String[] args) {
System.out.println("Hello World!");
B b = new B();
}
public Main(){
printVariable();
}
protected void printVariable(){
variable = "variable is initialized in Main Class";
}
}
public class B extends Main {
String variable = null;
public B(){
System.out.println("variable value = " + variable);
}
protected void printVariable(){
variable = "variable is initialized in B Class";
}
}
The output will be:
Hello World!
variable value = null
But if we change String variable = null;
to String variable;
we will have:
Hello World!
variable value = variable is initialized in B Class
The second output is more clear for me. So, as far as I know the sequence of inizialisation in Java like this:
- We go to the root of the class hierarchy (for Java it is always Object class), when we come to this root parent class:
- All static data fields are initialized;
- All static field initializers and static initialization blocks are executed;
- All non-static data fields are initialized;
- All non-static field initializers and non-static initialization blocks are executed;
- The default constructor is executed;
- Then we repeat the procedure for the underlying child class.
Also there is post which describes the behavior of the this
keyword in context of a superclass - Calling base class overridden function from base class method
Based on the rules given above, I assume to have sequence like this:
- We are going to create a new instance of class
B
; - We go to the part class
Main
; - Initialize
main.variable
with null; - Then we move to the default constructor of class
Main
; - Constructor calls method
b.printVariable()
in classMain
; (Why doesn't it callmain.printvariable
? We don't havethis
key word here.) - The field
b.variable
"variable is initialized in B Class" - Now we come back to the class
B
; - We should initialize field
b.variable
with null value, am I right?; - The default constructor of class
B
executed
Please, can someone give a complete and full explanation of how this inheritance inizialisation sequence works. And why changing String variable = null;
to String variable;
leads to another output.
First, you need to understand, what happens when you write
variable = null;
. When is that code executed. This basically determines the output.Before I begin, I should also mention that when you create an object of
class B
, theprintVariable()
function of the main class is not called. Instead, always theprintVariable()
of B will be called.Keeping this in mind, when you have
variable = null
, the execution for B's constructor will begin. FirstMain()
will be called, which will call the printVariable() method. At last,variable=null
, will be called overwriting thevariable
variable.In the other case, where you do not initialize
variable=null
, thevariable
set by theprintVariable()
function will not be overwritten, hence you get what you were expecting.In summary, this is the order of execution of statements, when you do
new B()
:This is a nice exercise! But it's not a fair question to ask junior developers. This one is for seniors. But to make this text useful during the technical interview, I'd modified it by adding an argument to the Main's constructor:
If the person will answer what will happen, then remove the argument and ask the original questions. If the person won't answer - there is no need to continue - s/he is junior.
You can also remove the protected qualifier in class B and ask what will happen if you have a goal not to hire this person :)
The sequence is:
So basically, the super object Main() is constructed before any intialisation events of class B. Which means variable=null occurs later. This makes sense as otherwise B could break the initialisation of Main.
Joshua Bloch covers a lot of good ground in his effective java book about how dangerous inheritance is to get right, I would recommend it.