Subclass Constructors

Introduction

Subclass constructors initialize both parent and child class members. They must call the parent class constructor using super().


Basic Concept

class Parent {
    Parent() {
        System.out.println("Parent constructor");
    }
}

class Child extends Parent {
    Child() {
        super();  // Call parent constructor (implicit if not specified)
        System.out.println("Child constructor");
    }
}

public class Main {
    public static void main(String[] args) {
        Child c = new Child();
    }
}

Output:

Parent constructor
Child constructor

Implicit super() Call

If you don’t call super(), Java automatically adds it.

class Parent {
    Parent() {
        System.out.println("Parent");
    }
}

class Child extends Parent {
    Child() {
        // super(); is automatically added here
        System.out.println("Child");
    }
}

Parameterized Parent Constructor

class Parent {
    String name;

    Parent(String name) {
        this.name = name;
        System.out.println("Parent: " + name);
    }
}

class Child extends Parent {
    int age;

    Child(String name, int age) {
        super(name);  // Must call parent constructor with parameter
        this.age = age;
        System.out.println("Child: " + age);
    }
}

public class Main {
    public static void main(String[] args) {
        Child c = new Child("John", 20);
        System.out.println("Name: " + c.name);
        System.out.println("Age: " + c.age);
    }
}

Output:

Parent: John
Child: 20
Name: John
Age: 20

Rules for super()

  1. Must be first statement in constructor
  2. Calls parent constructor
  3. Automatically added if not specified (calls no-arg constructor)
  4. Cannot use both super() and this() in same constructor
  5. If parent has only parameterized constructor, must call it explicitly

Complete Example

class Person {
    protected String name;
    protected int age;

    Person() {
        System.out.println("Person default constructor");
    }

    Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("Person parameterized constructor");
    }
}

class Student extends Person {
    private int rollNo;
    private double marks;

    // Constructor 1: No parameters
    Student() {
        super();  // Call Person()
        System.out.println("Student default constructor");
    }

    // Constructor 2: All parameters
    Student(String name, int age, int rollNo, double marks) {
        super(name, age);  // Call Person(String, int)
        this.rollNo = rollNo;
        this.marks = marks;
        System.out.println("Student parameterized constructor");
    }

    void display() {
        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
        System.out.println("Roll No: " + rollNo);
        System.out.println("Marks: " + marks);
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("Creating Student 1:");
        Student s1 = new Student();
        System.out.println();

        System.out.println("Creating Student 2:");
        Student s2 = new Student("John", 20, 101, 85.5);
        System.out.println();

        s2.display();
    }
}

Multiple Constructors

class Vehicle {
    String brand;
    int year;

    Vehicle() {
        this("Unknown", 2020);
    }

    Vehicle(String brand) {
        this(brand, 2020);
    }

    Vehicle(String brand, int year) {
        this.brand = brand;
        this.year = year;
    }
}

class Car extends Vehicle {
    int doors;

    Car() {
        super();  // Calls Vehicle()
        this.doors = 4;
    }

    Car(String brand) {
        super(brand);  // Calls Vehicle(String)
        this.doors = 4;
    }

    Car(String brand, int year, int doors) {
        super(brand, year);  // Calls Vehicle(String, int)
        this.doors = doors;
    }

    void display() {
        System.out.println("Brand: " + brand);
        System.out.println("Year: " + year);
        System.out.println("Doors: " + doors);
    }
}

Constructor Execution Order

class GrandParent {
    GrandParent() {
        System.out.println("1. GrandParent constructor");
    }
}

class Parent extends GrandParent {
    Parent() {
        super();  // Calls GrandParent()
        System.out.println("2. Parent constructor");
    }
}

class Child extends Parent {
    Child() {
        super();  // Calls Parent()
        System.out.println("3. Child constructor");
    }
}

public class Main {
    public static void main(String[] args) {
        Child c = new Child();
    }
}

Output:

1. GrandParent constructor
2. Parent constructor
3. Child constructor

Order: Top to bottom (parent → child)


Error: Parent Has No Default Constructor

class Parent {
    Parent(int x) {  // Only parameterized constructor
        System.out.println("Parent: " + x);
    }
}

class Child extends Parent {
    Child() {
        // super(); is implicit, but Parent() doesn't exist
        // ✗ Compilation Error!
    }
}

Solution:

class Child extends Parent {
    Child() {
        super(10);  // Must call parameterized constructor
    }

    Child(int x) {
        super(x);
    }
}

Using this() and super()

class Parent {
    String name;

    Parent(String name) {
        this.name = name;
    }
}

class Child extends Parent {
    int age;

    // Constructor 1
    Child() {
        this("Unknown", 0);  // Call constructor 2
    }

    // Constructor 2
    Child(String name, int age) {
        super(name);  // Call parent constructor
        this.age = age;
    }
}

Note: Cannot use both this() and super() in the same constructor.


Real-World Example

class BankAccount {
    protected String accountNumber;
    protected String holderName;
    protected double balance;

    BankAccount(String accountNumber, String holderName) {
        this.accountNumber = accountNumber;
        this.holderName = holderName;
        this.balance = 0;
        System.out.println("BankAccount created");
    }

    BankAccount(String accountNumber, String holderName, double balance) {
        this.accountNumber = accountNumber;
        this.holderName = holderName;
        this.balance = balance;
        System.out.println("BankAccount created with balance");
    }
}

class SavingsAccount extends BankAccount {
    private double interestRate;
    private double minimumBalance;

    SavingsAccount(String accountNumber, String holderName, double interestRate) {
        super(accountNumber, holderName);  // Call parent constructor
        this.interestRate = interestRate;
        this.minimumBalance = 1000;
        System.out.println("SavingsAccount created");
    }

    SavingsAccount(String accountNumber, String holderName,
                   double balance, double interestRate) {
        super(accountNumber, holderName, balance);
        this.interestRate = interestRate;
        this.minimumBalance = 1000;
        System.out.println("SavingsAccount created with balance");
    }

    void display() {
        System.out.println("Account: " + accountNumber);
        System.out.println("Holder: " + holderName);
        System.out.println("Balance: " + balance);
        System.out.println("Interest Rate: " + interestRate + "%");
        System.out.println("Min Balance: " + minimumBalance);
    }
}

public class Main {
    public static void main(String[] args) {
        SavingsAccount acc1 = new SavingsAccount("SA1001", "John", 4.5);
        System.out.println();

        SavingsAccount acc2 = new SavingsAccount("SA1002", "Alice", 5000, 5.0);
        System.out.println();

        acc2.display();
    }
}

Initialization Order

class Parent {
    int x = 10;  // 1. Parent field initialization

    Parent() {   // 2. Parent constructor
        System.out.println("Parent: x = " + x);
    }
}

class Child extends Parent {
    int y = 20;  // 3. Child field initialization

    Child() {    // 4. Child constructor
        super();
        System.out.println("Child: y = " + y);
    }
}

Order:

  1. Parent field initialization
  2. Parent constructor
  3. Child field initialization
  4. Child constructor

Common Mistakes

Mistake 1: super() Not First

// ✗ Wrong
class Child extends Parent {
    Child() {
        System.out.println("Child");
        super();  // Error: must be first
    }
}

// ✓ Correct
class Child extends Parent {
    Child() {
        super();  // First statement
        System.out.println("Child");
    }
}

Mistake 2: Using Both this() and super()

// ✗ Wrong
class Child extends Parent {
    Child() {
        super();
        this(10);  // Error: cannot use both
    }

    Child(int x) { }
}

Quick Reference

class Parent {
    String name;

    Parent(String name) {
        this.name = name;
    }
}

class Child extends Parent {
    int age;

    Child(String name, int age) {
        super(name);  // Must be first, calls Parent constructor
        this.age = age;
    }
}

// Usage
Child c = new Child("John", 20);
// Order: Parent constructor → Child constructor

Exam Tips

Remember:

  1. super() calls parent constructor
  2. Must be first statement
  3. Implicit super() if not specified
  4. Cannot use both this() and super()
  5. If parent has only parameterized, must call explicitly
  6. Constructors not inherited
  7. Execution order: parent → child
  8. Multilevel: GrandParent → Parent → Child
  9. Initialize parent first, then child
  10. Common error: forgetting to call parameterized parent

Common Questions:

  • What is super()?
  • When is super() called?
  • Where must super() be placed?
  • Constructor execution order?
  • Can we use this() and super() together?
  • What if parent has no default constructor?
  • Are constructors inherited?
  • Implicit vs explicit super()?