mitch
mitch

Reputation: 31

Java: Why a variable initialised by super class keeps value once object is created

I raised an issue at work, and simplified the code to reproduce it

public class Test {
    public void callTest(){ return; }
    public Test() { callTest(); }
}

public class Test1 extends Test{
    private Integer myInt;
    private Integer myNullInt = null;

    public Test1() {
      super();
    }

    @Override
    public void callTest() {
      myInt     = 25;
      myNullInt = 30;
    }

    @Override
    public String toString() {
      return "Test1{myInt=" + myInt + ", myNullInt=" + myNullInt +'}';
    }

    public static void main(String[] args) {
      Test1 t1 = new Test1();
      System.out.println(t1);
    }
}

With this a a result : Test1{myInt=25, myNullInt=null}

On my understanding, instance variable initializers should be executed after the call to super(). So why is 'myInt' getting a value. And even how can it be possible ?

Upvotes: 2

Views: 142

Answers (2)

Thomas Kläger
Thomas Kläger

Reputation: 21435

Instance initializers are executed after the call to super(); - that is why myNullInt is null. For myInt there is no instance initialzer involved.

The sequence of events is this:

  • the main method creates a new Test1() object
  • that means that the constructor of Test1 is called
  • that constructor in turn calls the super constructor Test()
    • the constructor of Test calls the callTest(); method
    • since the object under construction is a Test1 object, the callTest method from Test1 is called
    • Test1.callTest() sets the myInt field to 25, the myNullInt field to 30
    • after that, the constructor of Test ends
  • the constructor of Test1 resumes and executes the field initializer myNullInt = null;
  • since myInt doesn't have an initializer, its value is not changed

The process (including initialization with default values) is described in detail in the Java Language Specification, Creation of New Class Instances:

Whenever a new class instance is created, memory space is allocated for it with room for all the instance variables declared in the class type and all the instance variables declared in each superclass of the class type, including all the instance variables that may be hidden (§8.3).

[If there is not sufficient space ...] Otherwise, all the instance variables in the new object, including those declared in superclasses, are initialized to their default values (§4.12.5).

Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:

  1. / 2. [...]
  1. [...] an explicit or implicit invocation of a superclass constructor [...]
  1. Execute the instance initializers and instance variable initializers for this class [...]
  1. Execute the rest of the body of this constructor. [...]

Upvotes: 4

aksappy
aksappy

Reputation: 3400

The order of execution in your code looks like this.

  1. Constructor for Test1 is called.
  2. super invokes the constructor in Test.
  3. Since the call started from Test1, the overridden callTest is called, which sets the value for myInt to 25 and myNullInt to 30.
  4. super is completed, now proceeds to create the Test1 object.
  5. The instance variable for myNullInt is overwritten to null. Since there is no instruction for myInt, the value is unchanged.
  6. sysout call invokes the toString and prints the Test1 value.

The way instance variables are declared matters in inheritance.

Upvotes: 4

Related Questions