← Skill tree CS Skill Tree 0 CSCD211

this(...) Constructor Delegation

Textbook: BJP (Reges and Stepp)

Before You Start

Check each box you can do from memory. A box you cannot check yet is not a problem; it points you to a quick refresher, not a grade.

See Overloaded Constructors for a review of why multiple constructors exist and how the compiler distinguishes them.

Not sure? Take the 60-second self-check.

1. Two constructors. A class has Book(String title) and Book(String title, String isbn). Which is the “workhorse” (the one that should do all validation)?

Check

Book(String title, String isbn) is typically the workhorse because it has all the fields. The shorter constructor can delegate to it, supplying a default for the missing argument.

2. First statement. Where must this(...) appear in a constructor body?

Check

As the first statement. Any code before this(...) is a compile error.

3. What delegation does. When Book(String title) calls this(title, "UNKNOWN"), what runs first?

Check

The called constructor Book(String title, String isbn) runs first, fully. Then Book(String title)’s remaining body (after the this(...) call) runs. In a one-line delegation with no remaining body, only the called constructor runs.


Try This First

public Book(final String title) {
    this.title = title;       // (A)
    this(title, "UNKNOWN");   // (B)
}

Before reading: does this compile?

Check

No. this(...) must be the FIRST statement. Line (A) comes before the this(...) call. Compile error: “call to this must be first statement in constructor.”


What You Need To Walk In With

The Insight: this(...) calls another constructor in the same class. It must be the first statement because the called constructor initializes fields; any field assignments before this(...) would be overwritten. Delegation centralizes validation and initialization logic in one “workhorse” constructor and reduces duplication in the secondary constructor to a single forwarding call.

The first-statement rule can feel strict, but it prevents a real class of bugs: if the delegating constructor ran any code first, it could read fields that the workhorse had not yet initialized. The rule is conservative in the right direction. You can write this(...), write the workhorse once with every precondition check, and be confident that every object created through any overload goes through the same validation path. You can: write a two-constructor class using delegation; predict execution order when the call chain runs; use the inline-expression or private-static-helper workaround when you need to transform an argument before forwarding; and explain why this(...) and super(...) cannot coexist in the same constructor.


How It Works

The basic form

public class Book
{
    private String title;
    private String isbn;

    // workhorse: does all validation and assignment
    public Book(final String title, final String isbn)
    {
        if (title == null || isbn == null)
            throw new IllegalArgumentException("Bad parameter(s) in Book EVC");
        this.title = title;
        this.isbn  = isbn;
    }

    // convenience: one field, delegates for the missing one
    public Book(final String title)
    {
        this(title, "UNKNOWN");   // must be the FIRST and ONLY delegation call
        // optional additional body after the delegation
    }
}

When new Book("Java") is called: this(title, "UNKNOWN") runs the two-argument constructor first. The two-argument constructor validates, assigns, and returns. Then Book(String title)’s remaining body (empty here) runs.

The first-statement rule (JLS §8.8.7.1)

this(...) must be the first statement. Reasons: the called constructor initializes fields; any code before this(...) might read uninitialized fields or duplicate initialization.

This means you cannot compute local variables before calling this(...):

// ILLEGAL
public Engine(final int horsePower, final String manufacturer) {
    String mfg = manufacturer.trim();  // compute first
    this(mfg, horsePower);             // then delegate -- COMPILE ERROR
}

Workaround: inline the computation in the argument list or extract a private static helper:

public Engine(final int horsePower, final String manufacturer) {
    this(manufacturer.trim(), horsePower);   // inline: legal
}

Or use a private static method:

public Engine(final int horsePower, final String manufacturer) {
    this(trimManufacturer(manufacturer), horsePower);   // static helper: legal
}
private static String trimManufacturer(String m) { return m == null ? null : m.trim(); }

this(...) and super(...) are mutually exclusive

A constructor may have at most one of:

If neither is written, the compiler inserts an implicit super() (no-arg parent constructor call). Delegation via this(...) defers the super(...) responsibility to the ultimately-called constructor.

F17 Lab 6 / SP19 Lab 9 canonical example

Engine has two EVCs: Engine(String manufacturer, int horsePower) and Engine(int horsePower, String manufacturer). The first delegates to the second:

// F17.Lab6 / SP19.Lab9 Engine
public Engine(final String manufacturer, final int horsePower) {
    this(horsePower, manufacturer);   // reorder arguments, delegate
}

public Engine(final int horsePower, final String manufacturer) {
    if (horsePower <= 0 || manufacturer == null || manufacturer.isEmpty())
        throw new IllegalArgumentException("Bad parameter(s) in Engine EVC");
    this.horsePower   = horsePower;
    this.manufacturer = manufacturer;
}

The first constructor’s entire body is the delegation call. The second constructor is the workhorse.


Worked Example: Predict Then Check

class A {
    int x;
    int y;

    A(int x) {
        this(x, 0);
        System.out.println("A(int)");
    }

    A(int x, int y) {
        this.x = x;
        this.y = y;
        System.out.println("A(int,int)");
    }
}

new A(5);

Predict the output.

Reasoning

new A(5) calls A(int). The first statement is this(x, 0), which calls A(int, int) with x=5, y=0. A(int, int) assigns fields and prints "A(int,int)". Then A(int) resumes and prints "A(int)".

Show answer
A(int,int)
A(int)

The called constructor’s body runs first. After it returns, the calling constructor’s body continues.

Quick check

Check your understanding

Given: A(int x) { this(x, 0); System.out.println(“done”); } and A(int x, int y) { this.x = x; this.y = y; }. What is the output of new A(3)?

Tier 2 · BJP (Reges and Stepp), Ch 8


Common Misconceptions

Misconception 1: writing code before this(...)

Wrong mental model: “I need to compute a value before delegating.”

public Engine(int horsePower, String manufacturer) {
    String mfg = manufacturer.toUpperCase();  // compute
    this(mfg, horsePower);   // COMPILE ERROR
}

Why it breaks: JLS §8.8.7.1 requires this(...) to be the first statement. Code appearing before it is illegal.

How to correct: Move the computation into the argument list or a private static helper:

this(manufacturer.toUpperCase(), horsePower);   // inline: legal

Misconception 2: calling this(...) with the same signature (recursion)

Wrong mental model:A(int n) { this(n); } calls the default handling.”

Why it breaks: This is recursive constructor invocation: A(int n) delegates to A(int n), which delegates to itself, infinitely. The compiler detects constructor recursion and reports “recursive constructor invocation A(int)”.

How to correct: this(...) must target a constructor with a DIFFERENT signature. A(int n) { this(n, 0); } is legal if A(int, int) exists.

Source: JLS §8.8.7.

Quick check

Check your understanding

A student writes: public Car(int year) { String tag = “Y” + year; this(tag, year); }. What happens?

Tier 2 · BJP (Reges and Stepp), Ch 8


Formal Definition and Interface Contract

From JLS §8.8.7.1 (Explicit Constructor Invocations):

An explicit constructor invocation statement in a constructor body may invoke another constructor of the same class [...] using the keyword this. [...] The explicit constructor invocation must be the first statement of the constructor body.

From JLS §8.8.7:

It is a compile-time error if a constructor invokes itself, directly or indirectly, through a sequence of one or more explicit constructor invocations.


Mental Model

Think of this(...) as saying “before doing anything else here, go run that other constructor first.” It is an unconditional handoff to the workhorse constructor. When the workhorse finishes, control returns and the delegating constructor’s remaining body (if any) runs. The “first statement” rule enforces that the handoff happens before anything else, so fields are initialized by the workhorse before any code in the delegating constructor can read them.


Connections

Within CSCD 210/211: F17.Lab6.Engine, SP18.Lab2.Vehicle, SP19.Lab9.Engine, and W18.Lab1.Motor all demonstrate the two-EVC-with-delegation pattern. The delegation is typically a one-line constructor that reorders arguments and calls the workhorse.

Looking back: Overloaded Constructors established that multiple constructors exist and are distinguished by signature. This lesson adds the delegation mechanism for eliminating duplication.

Looking ahead: The next topic covers enum basics, a radically different form of constructor (enum constructors are private and called once per constant at class load time).


Practice

Level 1

Write a Motor class with two constructors: Motor(String manufacturer, double watts) and Motor(double watts, String manufacturer). The second delegates to the first via this(...).

Show answer
public class Motor
{
    private String manufacturer;
    private double watts;

    public Motor(final String manufacturer, final double watts)
    {
        if (manufacturer == null || manufacturer.isEmpty() || watts <= 0)
            throw new IllegalArgumentException("Bad parameter(s) in Motor EVC");
        this.manufacturer = manufacturer;
        this.watts        = watts;
    }

    public Motor(final double watts, final String manufacturer)
    {
        this(manufacturer, watts);   // reorder, delegate to workhorse
    }
}

Pattern from W18.Lab1.Motor.


Level 2

The following constructor does not compile. Identify the problem and fix it.

public Engine(final int horsePower, final String manufacturer)
{
    String mfg = manufacturer.trim();
    this(mfg, horsePower);
}
Show answer

Problem: this(...) is not the first statement. The local variable declaration String mfg = ... appears before it. Compile error: “call to this must be first statement in constructor.”

Fix: Inline the trim in the delegation call:

public Engine(final int horsePower, final String manufacturer)
{
    this(manufacturer == null ? null : manufacturer.trim(), horsePower);
}

Or extract a private static helper:

public Engine(final int horsePower, final String manufacturer)
{
    this(Engine.trim(manufacturer), horsePower);
}
private static String trim(final String s) { return s == null ? null : s.trim(); }

Level 3

Explain in 3-4 sentences why this(...) delegation improves maintainability compared to duplicating validation and assignment in both constructors.

Show answer

When validation and assignment live in only one workhorse constructor, any future change (adding a field, tightening a precondition, fixing a bug in assignment logic) is made in exactly one place. Without delegation, both constructors must be updated in sync; a missed update in one of them produces a class where some construction paths are inconsistent with others. Delegation enforces a single source of truth for initialization logic: the workhorse runs for every object construction, regardless of which overloaded entry point the caller used. The delegating constructor then becomes a thin adapter that translates one argument format into another and forwards.


Go Deeper (optional)

None of this is required to write correct code. If you are satisfied that you can write and debug delegation, move on.

The first-statement rule has a design history worth knowing. Java’s constructor call rules trace to a deliberate decision in the language specification to prevent a class of subtle bugs where a subclass constructor could observe an object in a partially initialized state. The constraint that this(...) must be first is the same constraint family as the rule for super(...): the language forces the entire initialization chain to run from the most specific superclass down before any constructor body touches fields. For two-argument-order overloads (the Engine pattern you saw), delegation is exactly the right tool, but for more complex object creation, production code reaches for the Builder pattern, which separates the construction sequence from the class itself and handles optional fields without an exponential number of constructors.

On the career side: constructor delegation for simple two-overload classes is idiomatic Java that you will see in every professional codebase. The bigger lesson is the one-responsibility principle at work: the workhorse constructor has one job (validate and assign), and the convenience constructor has one job (translate the argument shape and forward). D. Parnas described this decomposition idea in 1972 as “information hiding,” and it remains the organizing principle behind every modern API you will use.

The this(...) and super(...) mutual-exclusivity connects to a deeper structural point: every constructor chain must ultimately reach a single super(...) call to the root class (Object). The compiler guarantees this. When you write this(...), you are saying “I defer that super(...) responsibility to the called constructor.” The called constructor may itself call this(...), deferring further, but the chain must terminate at a constructor that calls super(...) (or inherits the implicit super()). The execution model is therefore a stack of delegations that unwinds from the root outward, constructing the object layer by layer.


Check Yourself

Close the notes and answer each one from memory, then reveal it. Pulling an idea back from memory is one of the strongest ways to make it stick.

Check your understanding

Where in a constructor body must the this(...) call appear?

Tier 1 · BJP (Reges and Stepp), Ch 8

A class has Engine(String manufacturer, int horsePower) and Engine(int horsePower, String manufacturer). The first constructor contains only this(horsePower, manufacturer). Which constructor is the workhorse?

Tier 1 · BJP (Reges and Stepp), Ch 8

What is the output of new A(5) given: A(int x) { this(x, 0); System.out.println(“A(int)”); } and A(int x, int y) { this.x = x; this.y = y; System.out.println(“A(int,int)”); }

Tier 2 · BJP (Reges and Stepp), Ch 8

Which of the following is a legal fix when computation is needed before calling this(...)?

Tier 2 · BJP (Reges and Stepp), Ch 8

A constructor contains this(...) as its first statement. Which statement about super(...) is correct for that same constructor?

Tier 3 · BJP (Reges and Stepp), Ch 8