22

Consider the code below:

  class Meal {
    Meal() { System.out.println("Meal()"); }
  }

  class Bread {
    Bread() { System.out.println("Bread()"); }
  }

  class Cheese {
    Cheese() { System.out.println("Cheese()"); }
  }
public static void sdadsdt(){

}
  class Lettuce {
    Lettuce() { System.out.println("Lettuce()"); }
  }

  class Lunch extends Meal {
    Lunch() { System.out.println("Lunch()"); }
  }

  class PortableLunch extends Lunch {
    PortableLunch() { System.out.println("PortableLunch()");}
  }

  class Sandwich extends PortableLunch {
    private Bread b = new Bread();
    private Cheese c = new Cheese();
    private Lettuce l = new Lettuce();
    public Sandwich() {
      System.out.println("Sandwich()");
    }
    public static void main(String[] args) {
      new Sandwich();
    }
  } 

Based on my understanding of class member initialization and the order of constructor execution, I expected the output to be:

Bread()
Cheese()
Lettuce()
Meal()
Lunch()
PortableLunch()    
Sandwich()

I believed that the class members were initialized even before the main method was called. However, when I ran the program, I received the following output:

Meal()
Lunch()
PortableLunch()
Bread()
Cheese()
Lettuce()
Sandwich()

I am confused as to why Meal(), Lunch(), and PortableLunch() are executed before Bread(), Cheese(), and Lettuce(), even though their constructors were called after.

Andreas Violaris
  • 2,465
  • 5
  • 13
  • 26
ade19
  • 1,150
  • 4
  • 13
  • 28
  • possible duplicate of [What is the order of the Constructors in this Java Code?](http://stackoverflow.com/questions/9904918/what-is-the-order-of-the-constructors-in-this-java-code) – allprog Oct 16 '13 at 15:30
  • See this Answer: [This](https://stackoverflow.com/questions/9586367/constructor-of-subclass-in-java) will make your concepts more clearer. – sarthakgupta072 Sep 20 '17 at 05:42

5 Answers5

26

These are instance fields

private Bread b = new Bread();
private Cheese c = new Cheese();
private Lettuce l = new Lettuce();

They only exist (execute) if an instance is created.

The first thing that runs in your program is

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

Super constructors are called implicitly as the first thing in each constructor, ie. before System.out.println

class Meal {
    Meal() { System.out.println("Meal()"); }
}

class Lunch extends Meal {
    Lunch() { System.out.println("Lunch()"); }
}

class PortableLunch extends Lunch {
    PortableLunch() { System.out.println("PortableLunch()");}
}

After the super() calls, instance fields are instantiated again before the constructor code.

The order, reversed

new Sandwich(); // prints last
// the instance fields
super(); // new PortableLunch() prints third
super(); // new Lunch() prints second
super(); // new Meal(); prints first
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • 3
    For further reading: [JLS 12.5 Creation of New Class Instances](http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.5) specifies the 5 steps for processing a constructor. Arguments, Alt Constructors (Recursive), Super Constructors (Recursive), Initializers, and Body – Dev Oct 16 '13 at 15:49
7

I think there are two things going on here that are throwing you off. The first is that main is a static method, where as the member variables b, c, and l are non-static instance variables. That means that they belong to the objects of the class, not the class itself. So when the class is initialized to run the main method, the contructors of Bread, Cheese, and Lettuce are not called, since no instances of Sandwich have been created.

Not until main actually run, and calls new Sandwich() are any objects actually constructed. At that point, the order of operations is:

  1. initialize member fields of the base class(es)
  2. run the base class(es) constructor(s)
  3. initialize member fields of this class
  4. run the constructor of this class

This is done recursively, so in this case, the order would be

  1. init fields of Meal (none)
  2. run constructor of Meal (prints "Meal")
  3. init fields of Lunch (none)
  4. run constructor of Lunch (prints "Lunch")
  5. init fields of PortableLunch (none)
  6. run constructor of PortableLunch (prints "PortableLunch")
  7. init fields of Sandwich (prints "Bread", "Cheese", and "Lettuce")
  8. run constructor of Sandwich (prints "Sandwich")

The purpose of this order is to ensure that the base class is fully initialized before any code in the subclass is run. This is needed because the within the constructor of the sub-class, it may call a method on the base class. Bad things would happen if that base class did not initialize its members first.

matt forsythe
  • 3,863
  • 1
  • 19
  • 29
6

even though their constructors where called after.

Not after, here how construstor method looks like to compiler :

public Sandwich(){
    super();// note this calls super constructor, which will call it's super and so on till Object's constructor
    //initiate member variables
    System.out.println("Sandwich()");
}
Eugen Halca
  • 1,775
  • 2
  • 13
  • 26
4

The first call in a constructor is always the super(...). This call is automatically inserted by the compiler if you don't write it down explicitly. No calls on the constructed object can happen before the call to super() returned. After super() finished, the fields are initialized in the order of appearance and then the rest of the constructor is executed.

allprog
  • 16,540
  • 9
  • 56
  • 97
0
private Bread b = new Bread();
private Cheese c = new Cheese();
private Lettuce l = new Lettuce();

These initializers are put into the Sandwich constructor by the compiler after the super call to it's parent class.

If these were static, then they would happen first, because static initializers happen on class load.

Cruncher
  • 7,641
  • 1
  • 31
  • 65