Skip to content
2 min read

Constructors in Java

A constructor is a special method that initializes an object when it's created. It has the same name as the class and no return type.


Types of Constructors

%%{init: {'theme': 'base', 'themeVariables': {'fontSize': '13px', 'fontFamily': 'Inter, -apple-system, sans-serif'}, 'flowchart': {'nodeSpacing': 30, 'rankSpacing': 50, 'padding': 12, 'curve': 'basis'}, 'sequence': {'actorMargin': 60, 'messageMargin': 40}, 'class': {'padding': 12}}}%%
flowchart LR
    A(("🏗️ Constructors")) --> B(["📭 Default<br/>no args"])
    A --> C(["📬 Parameterized<br/>with args"])
    A --> D(["📋 Copy Constructor<br/>clone an object"])

    style A fill:#BFDBFE,stroke:#93C5FD,color:#1E40AF
    style B fill:#DBEAFE,stroke:#93C5FD,color:#1E40AF
    style C fill:#BFDBFE,stroke:#93C5FD,color:#1E40AF
    style D fill:#FCA5A5,stroke:#FCA5A5,color:#1E40AF

Default Constructor

If you don't write any constructor, Java provides a default no-arg constructor automatically. The moment you write any constructor, the default disappears.

Java
public class Student {
    String name;
    int age;
    // Java provides: public Student() {} automatically
}

Student s = new Student();  // works fine
Java
public class Student {
    String name;
    int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

Student s = new Student();  // COMPILE ERROR — no default constructor!

Parameterized Constructor

Takes arguments to initialize the object with specific values.

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

    public Employee(String name, String department, double salary) {
        this.name = name;
        this.department = department;
        this.salary = salary;
    }
}

Employee emp = new Employee("Vamsi", "Engineering", 150000);

Constructor Overloading

A class can have multiple constructors with different parameter lists.

Java
public class Connection {
    private String host;
    private int port;
    private int timeout;

    public Connection() {
        this("localhost", 8080, 30000);
    }

    public Connection(String host, int port) {
        this(host, port, 30000);
    }

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

// All valid
Connection c1 = new Connection();                    // localhost:8080, 30s
Connection c2 = new Connection("db.server.com", 5432); // custom host:port, 30s
Connection c3 = new Connection("db.server.com", 5432, 5000); // fully custom

Constructor Chaining with this()

this() calls another constructor in the same class. Must be the first statement.

Java
public class User {
    private String name;
    private String email;
    private String role;

    public User(String name) {
        this(name, "no-reply@default.com");  // chains to 2-arg constructor
    }

    public User(String name, String email) {
        this(name, email, "USER");  // chains to 3-arg constructor
    }

    public User(String name, String email, String role) {
        this.name = name;
        this.email = email;
        this.role = role;
    }
}
%%{init: {'theme': 'base', 'themeVariables': {'fontSize': '13px', 'fontFamily': 'Inter, -apple-system, sans-serif'}, 'flowchart': {'nodeSpacing': 30, 'rankSpacing': 50, 'padding': 12, 'curve': 'basis'}, 'sequence': {'actorMargin': 60, 'messageMargin': 40}, 'class': {'padding': 12}}}%%
flowchart LR
    A(("🆕 new User - Vamsi")) -->|"this(name, default-email)"| B{{"🔗 User - Vamsi, no-reply@default.com"}}
    B -->|"this(name, email, USER)"| C{{"🔗 User - Vamsi, no-reply@default.com, USER"}}
    C --> D(["✅ Fields assigned"])

    style A fill:#DBEAFE,stroke:#93C5FD,color:#1E40AF
    style B fill:#BFDBFE,stroke:#93C5FD,color:#1E40AF
    style C fill:#FCA5A5,stroke:#FCA5A5,color:#1E40AF
    style D fill:#DBEAFE,stroke:#93C5FD,color:#1E40AF

Constructor Chaining with super()

super() calls the parent class constructor. If you don't write it, Java inserts super() (no-arg) automatically.

Java
public class Animal {
    String name;

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

public class Dog extends Animal {
    String breed;

    public Dog(String name, String breed) {
        super(name);  // MUST be first line — calls Animal(name)
        this.breed = breed;
        System.out.println("Dog constructor: " + breed);
    }
}

new Dog("Buddy", "Labrador");
// Output:
// Animal constructor: Buddy
// Dog constructor: Labrador

Copy Constructor

Creates a new object as a copy of an existing object. Java doesn't provide this by default — you write it yourself.

Java
public class Address {
    private String city;
    private String zip;

    public Address(String city, String zip) {
        this.city = city;
        this.zip = zip;
    }

    // Copy constructor
    public Address(Address other) {
        this.city = other.city;
        this.zip = other.zip;
    }
}

Address original = new Address("Bangalore", "560001");
Address copy = new Address(original);  // independent copy

Why not just use clone()? The clone() method is problematic — it bypasses constructors, has a confusing contract, and requires Cloneable interface. Copy constructors are cleaner and more explicit.


Private Constructor — Singleton & Utility Classes

A private constructor prevents external instantiation.

Singleton Pattern

Java
public class DatabaseConnection {
    private static final DatabaseConnection INSTANCE = new DatabaseConnection();

    private DatabaseConnection() {
        // private — no one can create another instance
    }

    public static DatabaseConnection getInstance() {
        return INSTANCE;
    }
}

Utility Class

Java
public class MathUtils {
    private MathUtils() {
        throw new AssertionError("Cannot instantiate utility class");
    }

    public static double round(double value, int places) {
        return Math.round(value * Math.pow(10, places)) / Math.pow(10, places);
    }
}

Constructor vs Method

Feature Constructor Method
Name Same as class name Any valid name
Return type None (not even void) Must have one
Called when Object is created (new) Explicitly by programmer
Inheritance Not inherited Inherited
this()/super() Can use (first line only) Cannot use
Default provided Yes (no-arg, if none written) No

Interview Questions

1. What happens if you write return inside a constructor?

You can write return; (empty return) to exit early, but you cannot write return value; — constructors have no return type so they can't return a value. This compiles fine: if (invalid) return;

2. Can a constructor be final, static, or abstract?

No to all three. final — constructors aren't inherited, so final is meaningless. static — constructors create instances, which is an instance-level operation. abstract — constructors must have a body to initialize the object.

3. In what order are constructors called in a 3-level inheritance chain?

Parent first, child last. For class C extends B, class B extends A: A()B()C(). Java always calls the parent constructor before the child, because the parent's state must be initialized before the child can use it.

4. Can this() and super() both appear in the same constructor?

No. Both must be the first statement in a constructor, so only one can exist. If you need both, chain through constructors: one constructor calls this() to another constructor in the same class, which then calls super().

5. What is the difference between a copy constructor and clone()?

Copy constructor: explicit, clean, type-safe, calls constructors normally. clone(): uses Cloneable marker interface, bypasses constructors, returns Object (needs casting), has a broken contract for deep vs shallow copy. Joshua Bloch (Effective Java) recommends copy constructors over clone().