Inheritance & Polymorphism

The super Keyword & Constructor Chaining

15 min Lesson 2 of 14

The super Keyword & Constructor Chaining

In the previous lesson you learned that a child class uses extends to inherit from a parent. But what happens when both the parent and the child need to be initialised? That is where the super keyword comes in. super lets you reach across the inheritance boundary and talk directly to the parent — calling its constructor or invoking one of its methods.

Why do parent constructors matter?

Every object in Java must be fully initialised before it can be used. When you create a child object, the parent's fields also exist inside that object, so the parent's constructor must run first to initialise them. Java enforces this automatically, but you need to understand the rules to write correct code.

Calling the parent constructor with super()

Use super(...) as the very first statement inside a child constructor to pass arguments up to the parent constructor.

// Parent class class Animal { private String name; private int age; public Animal(String name, int age) { this.name = name; this.age = age; System.out.println("Animal constructor: " + name + ", age " + age); } public String getName() { return name; } public int getAge() { return age; } } // Child class class Dog extends Animal { private String breed; public Dog(String name, int age, String breed) { super(name, age); // MUST be first — calls Animal(String, int) this.breed = breed; System.out.println("Dog constructor: " + breed); } public String getBreed() { return breed; } } // Main public class Main { public static void main(String[] args) { Dog d = new Dog("Rex", 3, "Labrador"); System.out.println(d.getName() + " is a " + d.getBreed()); } }

Output:

Animal constructor: Rex, age 3 Dog constructor: Labrador Rex is a Labrador

Notice the order: the parent constructor always runs before the child's own body. This guarantees that the parent's fields are ready by the time the child's constructor continues.

super() must be the first statement. Placing it anywhere else is a compile-time error. If you forget it entirely, Java silently inserts super() (the no-argument version) for you — but only if the parent has a no-arg constructor. If the parent requires arguments and you omit super(...), your code will not compile.

What if there is no explicit super()?

When the parent has a no-argument constructor, Java adds an implicit super() call for you:

class Vehicle { public Vehicle() { System.out.println("Vehicle created"); } } class Car extends Vehicle { public Car() { // Java inserts: super(); automatically System.out.println("Car created"); } }

Running new Car() prints "Vehicle created" first, then "Car created". The implicit call still follows the same rule — parent runs first.

Calling a parent method with super.method()

super is not only for constructors. You can also use it inside a method to call the parent's version of that same method. This is especially useful when you override a method but still want to reuse the parent's logic:

class Shape { public String describe() { return "I am a shape"; } } class Circle extends Shape { private double radius; public Circle(double radius) { this.radius = radius; } @Override public String describe() { // Reuse the parent message, then add our own detail return super.describe() + " — specifically a circle with radius " + radius; } } // Main public class Main { public static void main(String[] args) { Circle c = new Circle(5.0); System.out.println(c.describe()); } }

Output:

I am a shape — specifically a circle with radius 5.0
super.method() vs. super() — do not confuse them. super() (with parentheses, used alone as a statement) calls a parent constructor and must be the first line. super.someMethod() calls a parent method and can appear anywhere inside the child's method body.

Constructor execution order in a deeper hierarchy

The chain works the same way no matter how many levels of inheritance exist. Each level calls super() first, so execution flows from the top of the hierarchy downward:

class A { public A() { System.out.println("A"); } } class B extends A { public B() { System.out.println("B"); } } class C extends B { public C() { System.out.println("C"); } } // new C() prints: // A // B // C

Java always starts at the topmost ancestor and works its way down. You can rely on this order: by the time your constructor body runs, every parent above you has already finished initialising.

Every class ultimately extends Object. java.lang.Object sits at the top of every hierarchy. Its no-arg constructor is always the very first thing invoked, even if you never write super() — which is why you can call methods like toString() or equals() on any Java object without importing anything.

A practical example: employee hierarchy

class Employee { private String name; private double baseSalary; public Employee(String name, double baseSalary) { this.name = name; this.baseSalary = baseSalary; } public double calculatePay() { return baseSalary; } public String getName() { return name; } } class Manager extends Employee { private double bonus; public Manager(String name, double baseSalary, double bonus) { super(name, baseSalary); // initialise the Employee part this.bonus = bonus; } @Override public double calculatePay() { return super.calculatePay() + bonus; // reuse parent logic } } // Main public class Main { public static void main(String[] args) { Manager m = new Manager("Alice", 5000, 1500); System.out.println(m.getName() + " earns " + m.calculatePay()); } }

Output: Alice earns 6500.0

Here super(name, baseSalary) hands the shared data up to Employee, and super.calculatePay() reuses the base-salary logic so Manager does not duplicate it.

Summary

  • super(args) calls the parent constructor — must be the first line of any child constructor.
  • If omitted, Java inserts a no-arg super() automatically; if the parent has no no-arg constructor this causes a compile error.
  • super.method() calls the parent's version of a method and can appear anywhere in a child method.
  • Constructors always execute from the top of the hierarchy downward, so parent fields are always ready before child code runs.