OOP

17. Constructors and this / super Chaining

Constructors initialise objects; this(...) chains to another constructor in the same class; super(...) chains to the parent; every constructor must call one of these if not relying on the implicit no-arg super().

Java 21 (core language)

Explanation

If you define no constructors, the compiler generates a public no-argument constructor that calls super() implicitly. Once you define any constructor, the no-arg constructor is no longer generated unless you add it yourself.

this(args) must be the first statement in a constructor and calls another constructor in the same class (constructor chaining to reduce duplication). super(args) must similarly be the first statement and calls a parent constructor. You cannot use both in the same constructor.

If a parent class has no accessible no-arg constructor and the child's constructor doesn't explicitly call super(...), a compile error results. This often trips developers when adding a parameterised constructor to a base class and forgetting to update all subclasses.

Example

public class ConstructorChaining {
    static class Animal {
        final String name;
        final String sound;

        Animal(String name, String sound) {
            this.name  = name;
            this.sound = sound;
        }

        void speak() { System.out.println(name + " says " + sound); }
    }

    static class Dog extends Animal {
        final String breed;

        // Primary constructor
        Dog(String name, String breed) {
            super(name, "Woof");  // must be first statement
            this.breed = breed;
        }

        // Overloaded constructor chains to primary via this(...)
        Dog(String name) {
            this(name, "Mixed");  // must be first statement
        }
    }

    static class Config {
        final String host;
        final int    port;
        final int    timeout;

        Config(String host, int port, int timeout) {
            this.host    = host;
            this.port    = port;
            this.timeout = timeout;
        }

        // Default overloads chain to the primary
        Config(String host, int port) { this(host, port, 30); }
        Config(String host)           { this(host, 8080);      }
        Config()                      { this("localhost");      }
    }

    public static void main(String[] args) {
        new Dog("Rex", "Labrador").speak(); // Rex says Woof
        new Dog("Buddy").speak();           // Buddy says Woof (breed=Mixed)

        Config c1 = new Config();
        Config c2 = new Config("prod.example.com");
        System.out.println(c1.host + ":" + c1.port + " (timeout=" + c1.timeout + ")");
        System.out.println(c2.host + ":" + c2.port + " (timeout=" + c2.timeout + ")");
    }
}

Sources