javaoopinheritanceinstancesuper

Constructor invocation when we call super class constructor inside a sub-class,


Super Class

package objectAndClass;

public class Cycle {
    public int speed;
    public int gear;
    public Cycle(int sp, int gr) {
        this.speed = sp;
        this.gear = gr;
        System.out.println(this.hashCode());
        System.out.println(this.getClass().getName());
    }
    public void speedUp(int increment) {
        speed = speed + increment;
    }
    public void applyBrakes(int decrement) {
        speed =- decrement;
    }
    public void changeGear(int gr) {
        gear = gr;
    }

    public String toString() {
        return "Number of gears : "+gear+", And Speed of Bicycle is : "+speed;
    }
}

Sub Class

package inheritance;

import objectAndClass.Cycle;

public class MountainBike extends Cycle {
    public int seatHeight;
    public MountainBike(int speed, int gear, int sh) {
        super(speed, gear);
        System.out.println(this.hashCode());
        System.out.println(this.getClass().getName());
        this.seatHeight = sh;
    }
    public void adjustSeatHeight(int height) {
        seatHeight = height;
    }
    public String toString() {
        return (super.toString()+"\n Seat height is : "+seatHeight);
    }

    public static void main(String[] args) {
        MountainBike mb = new MountainBike(60, 4, 15);
        System.out.println(mb.toString());
    }

}

I used to apply inheritance (using super() inside sub-class constructor) thinking that the super class instance gets created first and then the sub-class instance. But then I came across several references like this Object Creation of Inherited Class - link 1, Object Creation of Inherited Class - link 2.

What I found interesting in these references like :

**It is mandatory that when an object is created, the constructor is for sure called but it is not mandatory when a constructor is called object creation is mandatory. **

While I also referred documentation of super, super. From there I came to know if a subclass constructor invokes a constructor of its superclass, either explicitly or implicitly, you might think that there will be a whole chain of constructors called, all the way back to the constructor of Object.

Summarising the references, what I believe is happening is that unlike normal constructor call, there won't be object creation specifically for super class in Inheritance even though there is an invocation of a chain of constructors. Its just single instance of sub-class which is in IS-A relationship, so basically has access to all properties and methods.

And I guess JVM somehow differentiates normal constructor call using new keyword and super() by not creating a super-class instance here. Is that so ? Is it all just class-loading when it comes to inheritance ?

I wonder if I am picturing it correctly here.


Solution

  • I guess JVM somehow differentiates normal constructor call using new keyword and super() by not creating a super-class instance here. Is that so?

    It's not the JVM, but the compiler, that distinguishes between these two forms. They get compiled differently.

    In Java bytecode, constructors are just methods with the special name <init>. The invokespecial instruction is used to invoke a constructor (among other things). Notice that this instruction requires that there is an object (and the parameters of the constructor) pushed onto the stack first. It is as if the constructor is a regular non-static method, that is called on an uninitialised instance. Think of calling the constructor as:

    someUninitalisedThing.<init>()
    

    On the other hand, there is the new instruction. This is what creates a new object, and pushes it onto the stack. Then <init> will be called on this object.

    That is, new SomeClass() is compiled to two instructions (using the bytecode syntax that IntelliJ uses):

    NEW SomeClass
    INVOKESPECIAL SomeClass.<init> ()V
    

    On the other hand, if you are already in a constructor, you already have access to an uninitialised object, on which the superclass constructor (or another constructor of this class) can be called. Recall that constructors are kind of like non-static methods as far as the JVM is concerned, and so we have access to this.

    So super() in a constructor would compile to:

    ALOAD 0
    INVOKESPECIAL SomeSuperclass.<init> ()V
    

    ALOAD 0 loads the local variable at index 0, which in this case is storing this.