Chapter 5 - Java for Beginners Course

Inheritance - Constructors

When talking about inheritance it is important to understand how objects in a hierarchy are created. For this section, let’s assume we have the following 2 classes:

We’ll have a simplified version of our Light class that only provides us with the turnOn/turnOff functionality.

public class Light {
    protected boolean on;

    public Light(boolean isLigthOn) {
        System.out.println("Light constructor");
        on = isLigthOn;
    }

    public void turnOn() {
        on = true;
    }

    public void turnOff() {
        on = false;
    }

    public void printLightDetails() {
        System.out.println("The light is on? " + on);
    }
}

You can see that the Light class has one constructor defined that has a boolean parameter as an input that defines if the light is on or off when it’s being created.

And we’ll add a child class called DimmableLight that will allow us to change the power/brightness of the light.

We’ll start with the basics of our class, no constructors added yet:

The example code in the project already has the constructors added as that’s the final version of the example. If you’re following this section and want to give this a try, just delete the DimmableLight constructors that have been defined.
public class DimmableLight extends Light {
    private int power;

    public void setPower(int power) {
        if (power < 0 || power > 100) {
            System.out.println("Invalid new power provided, expected 0-100 but got: " + power);
        }

        if (power == 0) {
            turnOff();
        } else {
            turnOn();
        }

        this.power = power;
    }

    public int getPower() {
        return power;
    }

    public void printDimmableLightDetails() {
        System.out.println("The dimmable light is on? " + on);
        if (on) {
            System.out.println("The dimmable light power is: " + power);
        }
    }
}

With the code above, we are defining a new DimmableLight class as a children class of Light that adds new state (power) and a couple of new behaviors to our Light class.

However, when you add the code above in your IDE as it is, you will get a compilation error stating that the "[…​] super constructor Light() is undefined […​]".

What does this error mean?

If you recall the section about constructors, you’ll note that our DimmableLight will have a constructor automatically added by the compiler because we haven’t defined any constructors. This implicit constructor that is added by the compiler will have these characteristics:

  • It is public

  • It doesn’t have any parameters

  • It invokes a parameter-less constructor in its superclass

As our super class Light doesn’t have a parameter-less constructor, we get a compilation error. We need to resolve this and invoke a constructor in our superclass that exists.

Invoking super class constructors

In the section about constructors we talked about how to invoke a constructor of the same class using the this(…​) keyword. In a similar way, we can invoke a specific constructor of the parent class (a.k.a superclass) using the super(…​) keyword.

For example, in our DimmableLight we’ll create two separate constructors as follows:

public class DimmableLight extends Light {
    //...

    public DimmableLight() {
        super(false);
    }

    public DimmableLight(boolean isLigthOn, int initialPower) {
        super(isLigthOn);
        System.out.println("DimmableLight constructor");
        setPower(initialPower);
    }

    //...
}
Adding just one of these two constructors would be enough, but we’re adding 2 to showcase a couple of things.

After we add a constructor to the DimmableLight class that invokes a valid constructor of its super class, we’ll see that our compilation errors are gone and we should be able to run our code.

Similar to the this(…​) keyword, if the super(…​) keyword is being used, then the super(…​) call must be the first line in a constructor. This means you can’t use both this(…​) and super(…​) in a single constructor.

However, we can use both this(…​) and super(…​) in different constructors. For example, we could change our first constructor as follows and achieve the same result:

public DimmableLight() {
    this(false, 0);
}

public DimmableLight(boolean isLigthOn, int initialPower) {
    super(isLigthOn);
    System.out.println("DimmableLight constructor");
    setPower(initialPower);
}

In both cases, our dimmable light will be off initially with a power of 0.

How does Java call my constructors?

All of the above implies that Java has an order of constructing objects and that it expects a subclass to invoke a constructor of its superclass during its creation process. If the compiler detects that this isn’t happening, like in our first example above, it will give a compilation error.

During runtime, when we create a new instance of DimmableLight, for example if we do, new DimmableLight(true, 50), Java will always create the superclass instance first and then the subclass instance.

Our class hierarchy currently looks like this: DimmableLightLightjava.lang.Object

In our case, the first object created by Java will be an instance of Object as it is the root of all classes in Java and is the superclass of Light. The second object is of type Light and that last one will be our DimmableLight instance.

Let’s give it a try:

In the example code run the JavaInheritanceAndConstructorsApp.
DimmableLight dimmableLight = new DimmableLight(true, 50);
dimmableLight.printDimmableLightDetails();

Output:

Light constructor
DimmableLight constructor
The dimmable light is on? true
The dimmable light power is: 50

In the example above, we can see that our Light constructor is invoked before our DimmableLight constructor as we expected.

Constructors with no this(…​) and no super(…​) defined

The use of this(…​) or super(…​) in a constructor is optional. If we don’t specify either in a constructor, then the compiler will automatically add a default super() call. This means, it will expect to be able to invoke a parameter-less constructor in the super class.

This means that adding a constructor like:

public DimmableLight() {
}

is equivalent to adding:

public DimmableLight() {
    super();
}
Code in GitHub

Get the code for this tutorial using the links below.

Project Repo
Download code for this step
Main class for this step
Dependencies

This is a list of recommended tutorials or courses that might be useful before starting this one.

Contents
Welcome to the Course!
Course Introduction
Chapter 1 - Building Blocks
Quick introduction to Java Variables Classes And Objects Class Example - Defining a class Object Examples - Creating instances Java Application Example - Running our first app Accessing class members - The dot operator Packages - Organizing the code
Chapter 2 - Primitives and Operators
Primitives Arithmetic Operators Assignment Operator Unary Operators Equality and Relational Operators Conditional Operators
Chapter 3 - Statements and Control Flow
Expressions Statements If-Then Statement If-Then-Else Statement More If Statements Switch Statement While and Do-While Statements For Statement Branching Statements Exception Handling
Chapter 4 - Code Example
Example Project - A Simple Vending Machine Adding money Delivering Items Giving Change
Chapter 5 - Classes and Interfaces
Introduction Access Level Modifiers Class Declaration - Class, Methods and Fields Class Declaration - Constructors Inheritance Basics Inheritance - Constructors Inheritance - Methods and Fields Polymorphism Abstract Classes and Methods Interfaces Static Class Members Class Composition Final Classes and Class Members Generic Classes
Chapter 6 - Base Object Behaviors
Introduction Type Comparison Type Casting Object Equality - The Contract Object Equality - Common Pitfalls Object String Representation Garbage Collection Object Comparison Primitive Wrappers and Autoboxing
Chapter 7 - Data Structures
Introduction Arrays - Declaration and Creation Arrays - Basic Operations Core Collection Interfaces List and ArrayList - Basic Operations ArrayList Internals Introduction to Hash Tables Map and HashMap - Basic Operations Set and HashSet - Basic Operations
Chapter 8 - Anonymous classes and lambdas
Introduction Filtering a List Anonymous Classes Lambdas Built-in Functional Interfaces
Chapter 9 - Streams
Introduction Creating Streams Intermediate Operations Terminal Operations