13

When does the instance variable get initialized? Is it after the constructor block is done or before it?

Consider this example:

public abstract class Parent {

 public Parent(){
   System.out.println("Parent Constructor");
   init();
 }

 public void init(){
   System.out.println("parent Init()");
 }
}

public class Child extends Parent {

private Integer attribute1;
private Integer attribute2 = null;

public Child(){
    super();
    System.out.println("Child Constructor");
}

public void init(){
    System.out.println("Child init()");
    super.init();
    attribute1 = new Integer(100);
    attribute2 = new Integer(200);
}

public void print(){
    System.out.println("attribute 1 : " +attribute1);
    System.out.println("attribute 2 : " +attribute2);
}
}

public class Tester {

public static void main(String[] args) {
    Parent c = new Child();
    ((Child)c).print();
    
}
}

OUTPUT:

Parent Constructor

Child init()

parent Init()

Child Constructor

attribute 1 : 100

attribute 2 : null


  1. When are the memory for the atribute 1 & 2 allocated in the heap ?

  2. Curious to know why is attribute 2 is NULL ?

  3. Are there any design flaws?

Gonen I
  • 5,576
  • 1
  • 29
  • 60
Akh
  • 5,961
  • 14
  • 53
  • 82

3 Answers3

13

When the memory for the atribute 1 & 2 are allocated in the heap ?

The memory for the object as a whole is allocated when the new operator is invoked, before the java.lang.Object constructor is entered. Memory is allocated for individual Integer instances in init, but there is no point when memory is allocated for individual properties -- only whole objects.

Curious to know why is attribute 2 is NULL ?

The init method is called in the super constructor, so attribute2 is assigned new Integer(200), and then the subclass constructor is invoked which applies property initializers in the order they appear in the source code. This line

private Integer attribute2 = null;

overwrites the value assigned by init() to null.

If you add a call to

 System.out.println("attribute 2 : " +attribute2);

right after your call to super(); then this will become apparent.

Are there any design flaws?

Calling sub-class methods before the base class has finished initializing is dangerous. The sub-class might rely on its base-class's invariants to protect its own invariants, and if the base-class constructor has not completed, then its invariants may not hold.

This is also likely to confuse C++ programmers and the like who would expect a call to init from the base class to invoke the base class's version since C++ rewrites the vtable pointer as constructors are entered.

See The Java Language Specification for all the gory details.

John Watts
  • 8,717
  • 1
  • 31
  • 35
Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
  • Thanks Mike, Design : I meant is it a good practice to have a child init() execute before its own constructor. Because here it defeats my purpose of child init(). whats your thought on this? – Akh Sep 06 '12 at 21:38
  • Also, is it good practice to have your instance variables initialized to null or not? – Akh Sep 06 '12 at 21:39
  • @AKh It's generally bad practise to call methods inside constructor that can be overridden by subclasses. You do not want your sub-classes to be able to break your class. – Fabian Barney Sep 06 '12 at 21:43
  • @AKh, Please see my edit. On `null`, if you can avoid having a variable be `null` ever, then you have eliminated one way your program can fail. For example, using a reference to an empty array instead of a `null` reference can simplify code. That said, sometimes `null` is the right value. If a map doesn't contain an entry for a key, then the convention used in Java is that `get` returns null for that key. – Mike Samuel Sep 06 '12 at 21:44
2

After consuming the answers and link provided here is my digest observation :


Here is the flow:

  1. Enter Child class constructor. Child(){ ... }

  2. Invoke explicit super() [invoking Parent class constructor].

  3. Enter Parent() { ... } class constructor

  4. Invoke implicit super() [invoking Object class constructor]

  5. Enter Object(){ } (No super constructor calls)

  6. Recursive call for super class constructor end here.

  7. Returns for Object class constructor

  8. Now in Parent class constructor...Instance initializers and Instance variable initializers of Parent class gets executed.

  9. Rest of the Parent class constructor is executed and returns

  10. Now in Child class constructor. Instance initializers and Instance variable initializers of Child class gets executed.

  11. Then rest of the Child class constructor is executed and finishes the object initialization process.


The reason attribute2 was NULL because

  1. attribute2 is assigned a value 200 @ step 9.
  2. But overridden to NULL in step 10

Are there any design flaws?

As Fabian Barney mention ::::: It's generally bad practise to call methods inside constructor that can be overridden by subclasses.

When the memory for the atribute 1 & 2 are allocated in the heap ? Still figuring out. Appreciate any pointers.

Thanks for Mike and Fabian

Akh
  • 5,961
  • 14
  • 53
  • 82
1

See the code and its console output below illustrating the flow of initialization. Notice that 'while constructing the object' methods and property of Parent class don't get used(called) at all.

Code

class Parent{
   static{ System.out.println("Static Parent initialization"); }

   int i=1234;
   {  System.out.println("Parent's instance initializer running");
      print("executed from Parent's instance initializer");
      update(1);
   }

   Parent() {
      System.out.println("Parent's constructor running");
      print("executed from Parent's constructor");
      update(2);
   }

   void print(String note) { System.out.println("never executed"); }
   void update(int newI){ System.out.println("never executed"); }
}

class Child extends Parent{
   static{ System.out.println("Static Child initialization"); }

   int i = 3;
   {System.out.println("Child's instance initializer; i=" + i); }

   Child(){super(); i=4; System.out.println("Child's constructor running. Setting i to 4");}

   void print(String note) { System.out.println("print(): '"+note.toUpperCase()+"' ; i="+i); }
   void update(int newI){i=newI;System.out.println("update("+newI+"): After update i="+i);}
}

class Context {
   public static void main(String[] args) {
      Parent parent = new Child();
      System.out.println("In main: child's i="+((Child)parent).i);
      System.out.println("In main: parent's i=" +parent.i);
   }
}

Output

Static Parent initialization

Static Child initialization

Parent's instance initializer running

print(): 'EXECUTED FROM PARENT'S INSTANCE INITIALIZER' ; i=0

update(1): After update i=1

Parent's constructor running

print(): 'EXECUTED FROM PARENT'S CONSTRUCTOR' ; i=1

update(2): After update i=2

Child's instance initializer; i=3

Child's constructor running. Setting i to 4

In main: child's i=4

In main: parent's i=1234