Constructors

A constructor is the special block that builds a usable object out of raw allocated memory — get its rules wrong and every object of that class starts life half-formed.

A constructor is a special block of code, tied to a class, that runs once when you create an object with new. Its job is to take a freshly allocated, zeroed-out block of memory and turn it into a fully initialized object — setting field values, enforcing invariants, and doing any setup the object needs before anyone can call a method on it.

Constructor Syntax

A constructor looks like a method but has no return type — not even void — and its name must exactly match the class name. It runs automatically when new ClassName(...) executes.

new Point(3, 4) allocates memory for a Point, then runs this constructor body with x=3, y=4 before the reference is handed back to p.

A constructor cannot be called like a normal method later (p.Point(5, 6) is illegal) — it only runs as part of object creation via new.

public class Point {
    private final int x;
    private final int y;

    // constructor: name matches the class, no return type
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

// usage
Point p = new Point(3, 4);

The No-Argument Constructor

A no-argument (or "no-arg") constructor takes no parameters. It is often used when a class has sensible default field values, or when construction and configuration are deliberately separated.

Every instance field already gets a default value (0, false, or null) before any constructor body runs, so this assignment is for clarity, not strictly required for correctness here.

public class Counter {
    private int count;

    public Counter() {
        count = 0; // explicit, though 0 is already the default for int
    }
}

Counter c = new Counter();

Parameterized Constructors

A parameterized constructor accepts arguments and uses them to set up the object's initial state, so every object can start with different data instead of a fixed default.

Validation belongs naturally in the constructor: it is the one place every Employee object is guaranteed to pass through, so an invalid object can never exist.

public class Employee {
    private final String name;
    private final double salary;

    public Employee(String name, double salary) {
        if (salary < 0) {
            throw new IllegalArgumentException("salary cannot be negative");
        }
        this.name = name;
        this.salary = salary;
    }
}

Employee e = new Employee("Priya", 75000.0);

Constructor Overloading

A class can declare multiple constructors as long as their parameter lists differ in number, order, or type — this is constructor overloading, resolved at compile time just like ordinary method overloading.

The compiler picks the matching constructor by argument count and type at each call site, exactly as it does for overloaded methods.

public class Rectangle {
    private final double width;
    private final double height;

    public Rectangle() {
        this(1.0, 1.0);
    }

    public Rectangle(double side) {
        this(side, side); // square
    }

    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
}

Rectangle unit   = new Rectangle();
Rectangle square = new Rectangle(5.0);
Rectangle rect   = new Rectangle(4.0, 9.0);

Constructor Chaining with this()

Inside one constructor, this(...) calls another constructor of the same class, letting simpler constructors delegate to a more complete one instead of duplicating initialization logic. Java requires this() to be the very first statement in the constructor body, and only one constructor call (this() or super()) may appear per constructor.

Range(5) is called.

Its body calls this(0, 5) as its first and only statement.

Control jumps to Range(int, int), which runs its full body and sets low and high.

Control returns to the one-argument constructor's body, which has no more statements.

Chaining avoids repeating the same validation or setup logic in every overloaded constructor — write it once in the "most complete" constructor and delegate to it.

public class Range {
    private final int low;
    private final int high;

    public Range(int low, int high) {
        this.low = low;
        this.high = high;
    }

    public Range(int high) {
        this(0, high); // must be first statement
    }
}

Default Constructor vs Explicitly Declared Constructor

If a class declares no constructors at all, the compiler automatically generates a public no-argument default constructor with an empty body. The moment you write any constructor yourself — even a parameterized one — that automatic default constructor is no longer generated.

This is one of the most common early Java bugs: adding a parameterized constructor silently removes the free no-arg one, breaking any code that relied on new B().

class A {
    // no constructor written — compiler supplies:  public A() { }
}

class B {
    private final int value;
    public B(int value) { this.value = value; }
    // no B() here, and none is generated automatically —
    // "new B()" would now fail to compile
}

Initialization Order

When new runs, Java performs initialization in a fixed order: first the superclass is fully constructed (implicitly or via an explicit super() call), then this class's instance field initializers and instance initializer blocks run in the order they appear in the source, and finally the constructor's own body executes.

The superclass constructor always completes before this class's field initializers run, which is why "Base()" prints first even though it is textually the outer call.

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

class Derived extends Base {
    int x = initX();
    { System.out.println("instance block"); }

    Derived() {
        System.out.println("Derived()");
    }

    static int initX() {
        System.out.println("field initializer for x");
        return 1;
    }
}

new Derived();
// Output:
// Base()
// field initializer for x
// instance block
// Derived()

Practical Usage

Constructors are the natural place to: validate arguments and fail fast with an exception, assign final fields (which must be assigned exactly once), establish class invariants, and wire together any objects this instance depends on.

Because the checks run before any BankAccount reference escapes, no other code can ever observe an account with a negative balance or a missing owner.

public class BankAccount {
    private final String ownerName;
    private double balance;

    public BankAccount(String ownerName, double openingBalance) {
        if (ownerName == null || ownerName.isBlank()) {
            throw new IllegalArgumentException("owner name required");
        }
        if (openingBalance < 0) {
            throw new IllegalArgumentException("opening balance cannot be negative");
        }
        this.ownerName = ownerName;
        this.balance = openingBalance;
    }
}

Complete Example

b2's constructor chains into the three-argument constructor, so the validation and assignment logic exists in exactly one place.

public class Book {
    private final String title;
    private final String author;
    private final int year;

    public Book(String title, String author, int year) {
        this.title = title;
        this.author = author;
        this.year = year;
    }

    // convenience constructor: chains to the full one with a default year
    public Book(String title, String author) {
        this(title, author, java.time.Year.now().getValue());
    }

    @Override
    public String toString() {
        return title + " by " + author + " (" + year + ")";
    }

    public static void main(String[] args) {
        Book b1 = new Book("Effective Java", "Joshua Bloch", 2018);
        Book b2 = new Book("Untitled Draft", "Anonymous");
        System.out.println(b1);
        System.out.println(b2);
    }
}

Mental Model

Think of new as a two-step process: the JVM first allocates raw, zero-filled memory shaped like the object, then hands that memory to the constructor to fill in. Nothing outside the constructor can observe the object mid-construction — by the time new returns a reference, construction is complete.

Quick Reference

Rule                                   Detail
------------------------------------   -------------------------------------------
Name                                   must match the class name exactly
Return type                            none (not even void)
Runs when                              a "new ClassName(...)" expression executes
Multiple constructors                  allowed via overloading (different params)
Delegating to another constructor      this(...) as the FIRST statement only
Default constructor                    auto-generated only if NO constructor is written
Order on construction                  superclass constructor -> field inits/blocks -> constructor body

Key Takeaways

A constructor shares the class name, has no return type, and runs automatically on new.

Writing any constructor removes the compiler's free no-argument default constructor.

this(...) chains to another constructor of the same class and must be the first statement.

Construction order is superclass first, then this class's field initializers and instance blocks, then the constructor body.

Constructors are the natural place to validate arguments and assign final fields.

public class User { private final String name; public User(String name) { this.name = name; } } // elsewhere User u = new User(); // compile error: no matching constructor public class User { private final String name; public User(String name) { this.name = name; } public User() { this("anonymous"); } // keep a no-arg option if callers need one }

Adding a parameterized constructor removes the compiler-generated no-arg constructor; if callers still need one, it must be declared explicitly.

public Range(int high) { System.out.println("building range"); this(0, high); // compile error: this() is not the first statement } public Range(int high) { this(0, high); System.out.println("building range"); }

A this() or super() call must be the first statement in a constructor body; nothing can execute before it.

public class Point { int x, y; public Point(int x, int y) { } // fields never assigned — every Point silently has x=0, y=0 } public class Point { int x, y; public Point(int x, int y) { this.x = x; this.y = y; } }

Declaring a parameter with the same name as a field does not assign it automatically — the assignment must be written, typically using this.field = parameter.

public class Config { public Config() { this(0); } public Config(int level) { this(); // compile error: constructors call each other in a cycle } } public class Config { public Config() { this(0); } public Config(int level) { // set up using level directly, no further chaining this.level = level; } private int level; }

Constructor chains must terminate; two constructors calling this() on each other creates a cycle the compiler rejects.

Why does a constructor have no return type, not even void?

A constructor does not "return" a value the way a method does — it initializes an object that the JVM already allocated. Giving it a return type would make it indistinguishable from an ordinary method with the same name as the class, so the language forbids one entirely.

What happens if a class defines only a parameterized constructor and code elsewhere calls new ClassName()?

It fails to compile. The compiler only supplies a default no-argument constructor when the class declares no constructors at all; once any constructor is written, new ClassName() requires a matching no-argument constructor to be declared explicitly.

Can a constructor call another constructor of the same class anywhere in its body?

No — only via this(...), and it must be the first statement. This guarantees delegation happens before any of this constructor's own initialization logic runs.

In what order do a superclass constructor, this class's field initializers, and this class's constructor body run?

Superclass constructor first (implicitly or via explicit super()), then this class's instance field initializers and instance initializer blocks in source order, then the remaining statements in this class's constructor body.

Why is validating arguments inside a constructor considered good practice?

The constructor is the one code path every object of that class must pass through before a reference to it exists anywhere. Validating there guarantees invalid objects can never be created, rather than relying on every caller to check afterward.

Why must final instance fields typically be assigned inside a constructor (or a field initializer)?

A final field must be assigned exactly once, and that assignment must complete before the constructor returns; the constructor (directly or through a chained this() call) is where that one-time assignment happens.

What is the practical benefit of constructor chaining with this() over duplicating setup code in each overloaded constructor?

Validation and initialization logic lives in exactly one place — typically the most complete constructor — so a future change to that logic (a new validation rule, an extra field) only needs to be made once instead of in every overload.

Write a Temperature class with a constructor that takes a Celsius double, throws IllegalArgumentException if it is below absolute zero (-273.15), and stores it in a final field.

public class Temperature { private final double celsius; public Temperature(double celsius) { if (celsius < -273.15) { throw new IllegalArgumentException("below absolute zero: " + celsius); } this.celsius = celsius; } public double getCelsius() { return celsius; } }

The constructor validates before assignment, so a Temperature object can never exist with an impossible value; the field is final, assigned exactly once.

What gets printed, and why?

Prints "Pair(1,2)". The no-arg constructor's first statement, this(1, 2), delegates to the two-argument constructor, which does the actual field assignment and printing; the no-arg constructor's body has nothing left to execute afterward.

Write a Vehicle class with three constructors: one taking (make, model, year), one taking (make, model) that chains to the first with year defaulted to 2024, and a no-arg one that chains to the second with "Unknown" for both make and model.

public class Vehicle { private final String make; private final String model; private final int year; public Vehicle(String make, String model, int year) { this.make = make; this.model = model; this.year = year; } public Vehicle(String make, String model) { this(make, model, 2024); } public Vehicle() { this("Unknown", "Unknown"); } }

Each simpler constructor delegates to the next-most-complete one via this(...) as its first statement, so the full validation/assignment logic exists only in the three-argument constructor.

What does this print?

2. Each call to new Widget() runs the constructor once, incrementing the static counter shared across all instances; two objects were created, so created ends at 2.

class Pair {
    int a, b;
    Pair() {
        this(1, 2);
    }
    Pair(int a, int b) {
        this.a = a;
        this.b = b;
        System.out.println("Pair(" + a + "," + b + ")");
    }
}
public class Main {
    public static void main(String[] args) {
        new Pair();
    }
}
class Widget {
    static int created = 0;
    Widget() { created++; }
}
public class Main {
    public static void main(String[] args) {
        Widget w1 = new Widget();
        Widget w2 = new Widget();
        System.out.println(Widget.created);
    }
}