Definition
Constructor delegation rules:
- this(args) calls another constructor in the same class. Used to avoid duplicating initialization logic.
- super(args) calls a parent class constructor. Ensures the parent is fully initialized before the child.
- Must be the first statement. You cannot put any code before this() or super(), and you cannot use both in the same constructor.
- Implicit super(). If you write neither this() nor super(), the compiler inserts
super()(no-arg) automatically.
When opening a new bank branch (child class), the head office (parent class) must be set up first (super()). You can also delegate within the branch: the full-service opening procedure (one constructor) can delegate to a basic setup procedure (this()) to reuse common steps. But the very first thing that happens must be either calling head office or calling the basic setup.
Understanding the Concepts
How does super() work?
public class Account {
private final String accountId;
private BigDecimal balance;
public Account(String accountId, BigDecimal balance) {
this.accountId = accountId;
this.balance = balance;
System.out.println("Account constructor: " + accountId);
}
}
public class SavingsAccount extends Account {
private double interestRate;
public SavingsAccount(String accountId, BigDecimal balance, double rate) {
super(accountId, balance); // MUST be first – initializes parent fields
this.interestRate = rate;
System.out.println("SavingsAccount constructor: rate=" + rate);
}
}
new SavingsAccount("SAV2001", new BigDecimal("500000"), 4.0);
// Output:
// Account constructor: SAV2001
// SavingsAccount constructor: rate=4.0
The parent constructor runs first, then the child constructor body.
How does this() work?
public class Account {
private final String accountId;
private BigDecimal balance;
private boolean active;
// Full constructor
public Account(String accountId, BigDecimal balance) {
this.accountId = accountId;
this.balance = balance;
this.active = true;
System.out.println("Full constructor");
}
// Convenience constructor delegates to the full one
public Account(String accountId) {
this(accountId, BigDecimal.ZERO); // this() calls the other constructor
System.out.println("Convenience constructor");
}
}
new Account("SAV2001");
// Output:
// Full constructor
// Convenience constructor
this() avoids duplicating the initialization logic.
What if the parent has no no-arg constructor?
public class Account {
// Only a parameterized constructor – no no-arg constructor
public Account(String accountId) {
System.out.println("Account: " + accountId);
}
}
public class SavingsAccount extends Account {
// This does NOT compile:
// public SavingsAccount() { } // ERROR: implicit super() expects no-arg, but none exists
// This compiles: explicitly call super with args
public SavingsAccount(String accountId, double rate) {
super(accountId); // explicit call to parent's parameterized constructor
}
}
If you do not write any constructor in Account, Java provides a default no-arg constructor. But the moment you write any constructor, the default disappears.
Can you use both this() and super()?
public class SavingsAccount extends Account {
// This does NOT compile:
// public SavingsAccount(String id) {
// super(id); // first statement
// this(id, 4.0); // ERROR: this() must also be first statement
// }
// The solution: chain this() to another constructor that calls super()
public SavingsAccount(String id) {
this(id, 4.0); // delegates to the other constructor
}
public SavingsAccount(String id, double rate) {
super(id); // this constructor calls super()
this.rate = rate;
}
}
Only one can be first. Use chaining to get both effects.
What is the complete construction order?
1. super() runs first (parent constructor)
2. Parent's field initializers and instance blocks run (in source order)
3. Parent's constructor body runs
4. Child's field initializers and instance blocks run
5. Child's constructor body runs
public class Account {
private boolean active = true; // step 2: field initializer
{ System.out.println("Account init block"); } // step 2: init block
public Account(String id) {
System.out.println("Account constructor"); // step 3
}
}
public class SavingsAccount extends Account {
private double rate = 4.0; // step 4: field initializer
{ System.out.println("Savings init block"); } // step 4
public SavingsAccount(String id) {
super(id); // step 1: triggers parent construction
System.out.println("Savings constructor"); // step 5
}
}
new SavingsAccount("SAV2001");
// Output:
// Account init block
// Account constructor
// Savings init block
// Savings constructor
What are common mistakes?
- Forgetting super() when parent has no no-arg constructor. Compiler error: "no suitable constructor found."
- Putting code before this() or super(). They must be the very first statement.
- Circular this() calls.
A() { this(1); }andA(int x) { this(); }creates infinite recursion. Compiler catches this. - Calling instance methods before super(). The object is not fully initialized yet – leads to NullPointerException or wrong state.
What should a senior engineer know?
- Records auto-generate a canonical constructor.
record Account(String id, BigDecimal balance) {}has an implicit all-args constructor. You can add a compact constructor for validation. - Lombok @AllArgsConstructor / @Builder generates constructors. Understand what they produce under the hood.
- In Spring, constructor injection is the preferred DI pattern:
public AccountService(AccountRepository repo) { this.repo = repo; }. Spring calls the constructor and injects dependencies.
Visual Overview
new SavingsAccount("SAV2001")
│
▼
SavingsAccount(String id)
│ super(id) ← must be first
▼
Account(String id)
│ super() ← implicit call to Object()
▼
Object() runs
▼
Account field initializers + init blocks
▼
Account constructor body
▼
SavingsAccount field initializers + init blocks
▼
SavingsAccount constructor body
▼
Object fully constructed
Rules:
this() or super() must be FIRST statement
Cannot use both in one constructor
If neither written → implicit super()
Parent no-arg missing + no explicit super(args) → COMPILE ERROR
Key Takeaway
this() delegates to another constructor in the same class, and super() calls the parent constructor. One of them must be the first statement in every constructor. If you write neither, the compiler inserts super() automatically.
The construction order is always parent first: super() runs, then the parent's field initializers and init blocks, then the parent's constructor body, then the child's field initializers and init blocks, then the child's constructor body.
If the parent class has no no-arg constructor, you must explicitly call super(args) or the code does not compile. Use this() chaining to avoid duplicating initialization logic across multiple constructors.
One sentence to remember: this() or super() must be the first statement, if neither is written super() is implicit, and the parent is always constructed before the child.
---