static block vs initializer block vs constructor in inheritance

oussama.elhadri picture oussama.elhadri · Feb 1, 2014 · Viewed 12.9k times · Source

i find this example and i want to understand the logic behind it ? how constructors and static blocks and initializer blocks works in inheritance ? in which stage each one is called ?

public class Parent {

    static {
        System.out.println("i am Parent 3");
    }

    {
        System.out.println("i am parent 2");
    }

    public Parent() {
        System.out.println("i am parent 1");
    }

}

public class Son extends Parent {

    static {System.out.println("i am son 3");}
    {System.out.println("i am son 2");}

    public Son() {
        System.out.println("i am son 1");
    }

    public static void main(String[] args) {
        new Son();
    }
}

the output is :

i am Parent 3
i am son 3
i am parent 2
i am parent 1
i am son 2
i am son 1

Answer

Pshemo picture Pshemo · Feb 2, 2014

You need to know that

  1. first instruction in constructor is invoking constructor of its parent class super(params) or if you want to use default constructor super(). In case of default constructor you don't have to write it explicitly.
  2. code in initializer block is moved to every constructor right after super(...) call
  3. static block is executed when class is initialized which is done after it is fully loaded (with its parent classes) by JVM.

So classes are compiled into classes similar to this.

public class Parent {
    static {
        System.out.println("Parent static block");
    }

    public Parent() {
        super();
        {
            System.out.println("Parent initializer block");
        }
        System.out.println("Parent constructor");
    }

}

public class Son extends Parent {

    static {
        System.out.println("Son static block");
    }

    public Son() {
        super();
        {
            System.out.println("Son initializer block");
        }
        System.out.println("Son constructor");
    }

    public static void main(String[] args) {
        new Son();
    }
}

To be able to execute main method from Son class JVM needs to load code of this class (and classes it extends). After class is fully loaded JVM initialize its static content which involves executing static blocks (yes, there can be more then one static blocks in one class). To fully load Son class JVM needs to know details about its parent class so it will fully load Parent class before Son which means it will also execute its static blocks before static blocks in Son class.

So output will look like:

  • Parent static block
  • Son static block

Now in main method you are invoking Son class constructor via new Son() which code looks like

super();
{
    System.out.println("Son initializer block");
}
System.out.println("Son constructor");

Since its super() refer to Parent class constructor, which is

super();// this will invoke Object constructor since Parent 
        // doesn't extend anything (which means it extends Object class)
{
    System.out.println("Parent initializer block");
}
System.out.println("Parent constructor");

as result you will see

  • Parent initializer block
  • Parent constructor

This handles Parent#constructor() executed with super() so next you will see code from Son constructor after super() which will generate

  • Son initializer block
  • Son constructor

To see that classes will be loaded even before you use Son constructor or even main method you can just print something before using Son constructor like

System.out.println("ABC                      // before new Son()");
new Son();

which will result in

Parent static block
Son static block
ABC                      // before new Son()
Parent initializer block
Parent constructor
Son initializer block
Son constructor