Object creation process: Inheritance

We know that every class in Java is a part of an inheritance hierarchy. Either it extends a superclass explicitly, or the Object class implicitly. So, inheritance is always there. But most of the beginners begin to get confused with this topic – Object creation process, only when they actually learn about Inheritance, by extending an explicit superclass. Few of the doubts that might come in their minds are: –

  • How can we access this keyword in the constructor, even though the object has not been constructed yet?
  • When we instantiate a subclass (which they always do, but don’t know initially), does the super class also gets instantiated?
  • If the 2nd point is true, then how on earth does the super class gets instantiated, if it is an abstract class?

Quite interesting questions, aren’t they? Well, I’ll talk about them towards the end of this post, after I explain the bits and pieces about the Object Creation Process.

So, when is an Object created?

Object creation can be explicit or implicit: –

  • Explicit Object Creation takes place when we write a Class Instance Creation expression (one where you make use of new keyword). In it’s simplest form, a Class Instance Creation expression looks like: –
    new Apple();

    Assuming, we have a class named Apple somewhere on our machine, under default package, or the corresponding package being imported at the top of the class. Rest of the post will be an elaboration of this process only. Also note that, I have not assigned any reference to the newly created object here. Because, that is not needed here.

  • Implicit Object Creation, on the other hand, keeps on happening throughout our code. Some of the examples where an implicit object is created are: –
    • When you perform a String Concatenation operation (excluding the one that takes place between compile-time constants, viz, string literals), a new String object is created for each concatenation (When I say, new object is created, I mean object that is created on Heap and not on literal pool).
    • When you invoke a method on an immutable object, for e.g. String, the modified object returned is always a new object. In other words, any method of String class, or any other class, whose objects are immutable for that matter, will create and return a new object.

    Likewise, there are many more situations, where a new object is being created, and most of the time it goes unnoticed to beginners. Anyways, this is not the matter of discussion of this post, so let’s not extend it any further and move ahead with the actual topic.

Explicit Object Creation (Behind the scene stuffs): –

The object creation process involves several behind the scene steps, which I’ll try to explain in most basic form.

First and foremost thing to understand is, the object is created by the new operator and not by the constructor. Constructor is only used to initialize the state of the newly created object.
Whenever a class instance is created (by new operator), memory is allocated for it, including memory for all the instance fields in that class and all the superclasses of that class. Then all the instance fields for that particular instance is initialized with their default values.

At this point, the object is already created. Now, for this newly created object, the constructor following the new keyword in the object creation expression is invoked to initialize the state of the object. That constructor in turn can invoke another constructor of the same class explicitly using this() call, passing appropriate arguments if needed. If the constructor does not invoke any constructor using this(), then an implicit or explicit call to the immediate superclass constructor is made using super() call.

Note that, every constructor must have either a this(parameters) call or a super(parameter) call as the first statement. If we don’t insert either of them, then the compiler inserts a super() call as the first statement of every constructor, which will invoke the 0-arg constructor of the immediate superclass.

Eventually, at the end of this chaining of constructor invocation, the last constructor which is invoked is that of Object class. So, the first constructor to execute is Object class constructor. Then the rest of the body of each sub class constructor is executed in order.

If any class has defined an instance initializer block, then the compiler adds that block to every constructor of that class, immediately after the super or this call. Thus, all the instance initializer blocks are also executed for each super class.

At any point, in the process of this recursive invocation, and execution of all the constructors in the inheritance hierarchy, if an exception is thrown, then that particular constructor invocation ends abruptly. In which case, the whole procedure ends abruptly.

Finally, when all the constructors complete the execution process successfully, the new operator returns a reference to the object.

Code Talks Better: –

package com.rjcodeblog;

import java.math.BigDecimal;

class Fruit {
    /** Private instance variable **/
    private BigDecimal pricePerKg;

    public Fruit() {
        this.pricePerKg = BigDecimal.ZERO;
        System.out.println("Superclass 0-arg constructor");
    }

    public Fruit(BigDecimal pricePerKg) {
        this.pricePerKg = pricePerKg;
        System.out.println("Superclass parameterized constructor");
    }
}

class Apple extends Fruit {
    /** Private instance variable **/
    private String color;

    /** A no-arg constructor **/
    public Apple() {
        this.color = "";
        System.out.println("Subclass 0-arg constructor");
    }

    public Apple(String color, BigDecimal pricePerKg) {
        super(pricePerKg);  // If we don't add this, compiler will add super()
        this.color = color;
        System.out.println("Subclass parameterized constructor");
    }

    /** Getters and Setters **/
}

public class Juicer {
    public static void main(String[] args) {
        Apple fake = new Apple();
        Apple real = new Apple("red", new BigDecimal("50"));
    }
}

So, we have a superclass – Fruit with 1 instance field, and 2 constructors – 0-arg and parameterized. In addition, we have one subclass – Apple with 1 instance field, and 2 constructors. You can notice that, we have added an explicit super call in parameterized constructor. This is because, if we don’t add it, compiler will add a super call to 0-arg constructor of super class, which we don’t want.

So, till now you might have got the output of the above program right? Let’s see if I get it right or not. And this is what I’ve got: –

Superclass 0-arg constructor
Subclass 0-arg constructor
Superclass parameterized constructor
Subclass parameterized constructor

So, this is all in this topic for now. Note that I’ve not covered all the aspects of the complete process, but only a short overview. If you want to learn more about this topic, you can always refer to the Java Language Specification.

Further Reading: –

Now, to end this post, let’s get back to the questions that I pointed out at the beginning of this post: –

  • How can we access this keyword in the constructor, even though the object has not been constructed yet?

Now that you understand that the constructor is not responsible for the creation of object. It’s the new operator that creates an object. So, it is probably clear that while you are executing the constructor, the object is already being created, and this refers to that created object.

  • When we instantiate a subclass (which they always do, but don’t know initially), does the super class also gets instantiated?

No. As I said earlier, the object is created only of the class, whose constructor is written as the part of Instance Creation Expression. That is, the class constructor that is followed by the new keyword. And then, on the newly created object, the constructor of that class, and eventually, all the super classes are invoked to initialize the state of that object.

  • If the 2nd point is true, then how on earth does the super class gets instantiated, if it is an abstract class?

I think you got the answer of this one now. Still, I will revise it for my own sake. The abstract class is not being instantiated, rather only it’s constructor is invoked to initialize the state of object that is the part of that class.