00:00

Constructor Chaining in Java – this() and super() Explained

Constructor chaining means one constructor calling another. Java supports two kinds: calling another constructor of the same class with this(...), and calling a constructor of the parent class with super(...). Chaining removes duplicated initialisation code and guarantees that every part of an object, including the parts it inherits, is set up correctly.

This tutorial explains both forms with runnable examples, shows the order in which chained constructors run, and lists the rules the compiler enforces.

1. Why Chain Constructors?

  • No duplication: validation and assignment logic lives in one constructor; the others delegate to it.
  • Sensible defaults: short constructors supply default values and pass them on.
  • Correct inheritance: each class initialises its own fields, after its parent has initialised the inherited ones.

2. Chaining Within a Class: this(...)

Overloaded constructors can call each other with this(...). A common pattern is to let the constructor with the most parameters do all the work, and have the others call it with default values:

ThisChaining.java
public class ThisChaining {
    static class Order {
        final String item;
        final int quantity;
        final String delivery;

        Order(String item) {
            this(item, 1);                          // calls the 2-argument constructor
            System.out.println("  Order(item) finished");
        }

        Order(String item, int quantity) {
            this(item, quantity, "standard");       // calls the 3-argument constructor
            System.out.println("  Order(item, quantity) finished");
        }

        Order(String item, int quantity, String delivery) {   // all the real work happens here
            if (quantity <= 0) throw new IllegalArgumentException("quantity must be positive");
            this.item = item;
            this.quantity = quantity;
            this.delivery = delivery;
            System.out.println("  Order(item, quantity, delivery) finished");
        }

        @Override public String toString() { return quantity + " x " + item + " (" + delivery + ")"; }
    }

    public static void main(String[] args) {
        System.out.println("new Order(\"book\"):");
        System.out.println(new Order("book"));
        System.out.println("new Order(\"pen\", 5, \"express\"):");
        System.out.println(new Order("pen", 5, "express"));
    }
}
Output
new Order("book"):
  Order(item, quantity, delivery) finished
  Order(item, quantity) finished
  Order(item) finished
1 x book (standard)
new Order("pen", 5, "express"):
  Order(item, quantity, delivery) finished
5 x pen (express)

Notice the output order: the most complete constructor finishes first, then control returns to each caller in turn, just like nested method calls.

3. Chaining to the Parent Class: super(...)

Every constructor of a subclass must start by running a constructor of its parent class. Use super(...) to choose which one and pass arguments. In a three-level hierarchy, the chain runs from the top of the hierarchy down:

SuperChaining.java
public class SuperChaining {
    static class Person {
        final String name;
        Person(String name) {
            this.name = name;
            System.out.println("1. Person constructor: name set");
        }
    }

    static class Employee extends Person {
        final String company;
        Employee(String name, String company) {
            super(name);                            // must be the first statement
            this.company = company;
            System.out.println("2. Employee constructor: company set");
        }
    }

    static class Manager extends Employee {
        final int teamSize;
        Manager(String name, String company, int teamSize) {
            super(name, company);
            this.teamSize = teamSize;
            System.out.println("3. Manager constructor: team size set");
        }
    }

    public static void main(String[] args) {
        Manager m = new Manager("Asha", "Acme", 8);
        System.out.println(m.name + " manages " + m.teamSize + " people at " + m.company);
    }
}
Output
1. Person constructor: name set
2. Employee constructor: company set
3. Manager constructor: team size set
Asha manages 8 people at Acme

The parent part of the object is always fully initialised before the child's constructor body runs, so the child can safely use inherited fields.

4. Implicit super() Calls

If a constructor does not start with this(...) or super(...), the compiler silently inserts super();, a call to the parent's no-argument constructor. That works only if such a constructor exists:

ImplicitSuper.java
public class ImplicitSuper {
    static class Animal {
        Animal() { System.out.println("Animal() runs first, even without an explicit super()"); }
    }

    static class Dog extends Animal {
        Dog() {
            // the compiler inserts super(); here
            System.out.println("Dog() runs second");
        }
    }

    // If the parent has NO no-argument constructor, the child MUST call super(...) explicitly
    static class Vehicle {
        final int wheels;
        Vehicle(int wheels) { this.wheels = wheels; }
    }

    static class Bike extends Vehicle {
        Bike() { super(2); }                        // without this line: compile error
    }

    public static void main(String[] args) {
        new Dog();
        System.out.println("Bike wheels: " + new Bike().wheels);
    }
}
Output
Animal() runs first, even without an explicit super()
Dog() runs second
Bike wheels: 2

Without the explicit super(2) in Bike, compilation fails because Vehicle has no no-argument constructor:

javac output
Bike.java:2: error: constructor Vehicle in class Vehicle cannot be applied to given types;
class Bike extends Vehicle { Bike() { } }
                                    ^
  required: int
  found:    no arguments
  reason: actual and formal argument lists differ in length

5. Rules of Constructor Chaining

  • this(...) or super(...) must be the first statement in a constructor (Java 25 relaxes this, allowing simple statements before the call that do not use this).
  • A constructor can call either this(...) or super(...), never both.
  • Calls must not form a cycle: A() calling A(int) calling A() is a compile error ("recursive constructor invocation").
  • Every chain of this(...) calls ends in a constructor that calls super(...), explicitly or implicitly.
  • Arguments to this(...)/super(...) cannot use instance fields or methods of the object being built, because it is not initialised yet (static methods are fine).
  • Chaining all the way up ends at Object(), the root of every class.

6. this(...) vs super(...)

Featurethis(...)super(...)
CallsAnother constructor of the same classA constructor of the parent class
PurposeReuse code between overloaded constructorsInitialise inherited state
Inserted automatically?NoYes, super(), if you write neither call
PositionFirst statementFirst statement

7. When Chains Get Long: Builders

Many overloaded constructors calling each other ("telescoping constructors") become hard to read when a class has many optional parameters: new Pizza("large", "thin", true, false, true) says little. Consider a builder (Pizza.builder().size("large").extraCheese().build()) or a record with static factory methods instead.

8. Summary

  • Constructor chaining is one constructor calling another with this(...) or super(...).
  • this(...) reuses code between constructors of the same class.
  • super(...) initialises the parent part of the object first; the compiler adds super() if you do not.
  • The call must come first, only one call is allowed, and cycles are forbidden.
  • Chains run from the most general class down to the most specific one.

Related Tutorials