Heisenberg
Heisenberg

Reputation: 3193

JAVA initialization blocks

As some sources say, the Java instance initialization blocks are executed whenever instance is created or right before constructor. But imagine this case:

public class Foo {

    {
        System.out.println("Foo init");
    }

    public Foo()
    {

        {
            System.out.println("Foo constr");
        }
    }
}

public class Main extends Foo {

    {
        System.out.println("Main init");
    }

    public Main()
    {

        {
            System.out.println("Main constr");
        }
    }

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

And the output is (as predicted):

Foo init
Foo constr
Main init
Main constr

So my question is - what is right definition of instance initialization block, because it obviously isn't executed right before constructor, because output should be

Main init
Foo init
Foo constr
Main constr

because Main() constructor is called before call to super() and Main initialization block should be first.

Upvotes: 2

Views: 378

Answers (6)

KP_JavaDev
KP_JavaDev

Reputation: 222

See how this code works internally :

class Foo {

    {System.out.println("Foo init");}

    public Foo()
    {

        {System.out.println("Foo constr");}
    }
}



class Main extends Foo {

    {System.out.println("Main init");}

    public Main()
    {

        {System.out.println("Main constr");}
    }
    public static void main(String[] args) {

        new Main();
    }
}

Step 1 : The JVM calls the main() method of Main class

Step 2 : Constructor Main() have internally super() which is given by JVM if you are not using this(), hence super will call super class constructor i.e Foo() of super class.

Step 3 : Now before calling the Foo of super class, the JVM will check is there any IIB i.e instance initialization Block, hence, "Foo init" will be printed before printing the "Foo constr"

Now output till now is :

Foo init 
Foo constr

Step 4: Our control come back to the current constructor and again before execution the current construstor JVM will call IIB i.e instance initialization Block and "Main init" will be printed. Then finally "Main constr"

So Finally out is :

Foo init
Foo constr
Main init
Main constr

Actually the first call of any Constructor is always Super() or this(). you are creating new object using new Main(); and of course this will give call to constructor, Constructor is always called to initialize the object.

Upvotes: 0

Eyal Schneider
Eyal Schneider

Reputation: 22446

The last statement is incorrect. Main() is executed after Foo(), because a class constructor is executed after its super constructor has finished. For more details see this part of the spec, which deals with implicit and explicit super constructor calls.

Upvotes: 0

Makoto
Makoto

Reputation: 106490

There's a specific initialization procedure explained in the JLS, but let me distill the most critical parts:

  • What happens in terms of initializing a class is implementation-dependent of the JVM.
  • The super class is initialized before its subclasses (step 7) if the super class has not yet been initialized.
  • Evaluate all static initializers and fields as if they were a single block in textual order. That last part is important; it means that what's seen first is initialized first.

This is why you see the behavior you do - because Main is a subclass to Foo, it isn't yet initialized, so its static block isn't been evaluated at that moment.

Consequently, Main's constructor isn't executed until after Foo's constructor, since there is an implicit call to super() in the subclass.

Upvotes: 0

Alexei Kaigorodov
Alexei Kaigorodov

Reputation: 13535

The code is converted by compiler to something like this:

public class Main extends Foo {
  void _init()
  {System.out.println("Main init");}

  public Main()
  {
    super();
    _init();
    {System.out.println("Main constr");}
  }

}

The main rules are:

  • super() is called before any initialization code of the current class
  • initializer blocks are called before the body of the constructor

Upvotes: 0

TheLostMind
TheLostMind

Reputation: 36304

        new Main(); 

the above state ment will first goto Main(). But before execution of anything in Main(), super() is called. So, Foo() is called. Now, in Foo() a check is made to see instance initialization block. So, you get. "Foo init" . Next the statements in Foo() are executed. So, you get- "Foo constr". Next the control is returned to Main() which now checks whether an initialization block exists for Main class. So, "Main Init" is printed.. then other statements of Main() are printed. The definition is right.. The understanding.. well... depends on how you see it...

Upvotes: 0

Elliott Frisch
Elliott Frisch

Reputation: 201507

No. The initialization blocks are copied directly into the constructor(s). Obviously there is an implicit super in there as well. So your example becomes

public class Foo {
  public Foo()
  {
    {System.out.println("Foo init");} // initializer.
    {System.out.println("Foo constr");}
  }
}

public class Main extends Foo {
  public Main()
  {  
    super(); // super constructor.
    {System.out.println("Main init");} // initializer.
    {System.out.println("Main constr");}
  }
  public static void main(String[] args) {
    new Main();
  }
}

Which explains your observed behavior of

Foo init
Foo constr
Main init
Main constr

Upvotes: 4

Related Questions