Java Constructors
Java Constructors
A constructor is a special method that runs automatically every time a new object is created. It is responsible for setting up the object's initial state — assigning values to fields before any other code touches the object. Without a constructor, you would have to manually initialise every field after every new call, which is both verbose and error-prone.
Understanding constructors properly — especially constructor chaining and the rules that govern them — is essential for every Java interview and for writing clean object creation logic in production.
What Is a Constructor in Java?
A constructor is a block of code that is called automatically when an object is created with the new keyword. It has three distinguishing characteristics that separate it from a regular method:
- ›The constructor name must exactly match the class name
- ›It has no return type — not even
void - ›It cannot be called directly like a method; it is invoked only through
new
Every class in Java has at least one constructor. If you do not write one, the compiler silently generates a default no-argument constructor for you. The moment you write any constructor yourself, the compiler stops generating the default.
Types of Constructors in Java
Java has four constructor forms, each solving a different object creation scenario.
| Constructor Type | Defined By | Parameters | Purpose |
|---|---|---|---|
| Default (no-arg) | Compiler (if none written) | None | Creates object with default field values |
| No-arg | Developer | None | Creates object with custom default state |
| Parameterised | Developer | One or more | Creates object with caller-supplied values |
| Copy | Developer | Same class object | Creates a new object by copying another |
Default Constructor
If you write no constructor at all, the Java compiler generates a default constructor — a no-argument constructor with an empty body. It is invisible in your source code but exists in the compiled bytecode.
1// File: SimpleProduct.java
2
3public class SimpleProduct {
4
5 String name; // initialised to null by JVM default
6 double price; // initialised to 0.0 by JVM default
7 int stock; // initialised to 0 by JVM default
8
9 // No constructor written — compiler generates:
10 // public SimpleProduct() {}
11}1// File: DefaultConstructorDemo.java
2
3public class DefaultConstructorDemo {
4
5 public static void main(String[] args) {
6
7 // Compiler-generated default constructor is called here
8 SimpleProduct product = new SimpleProduct();
9
10 System.out.println("Name : " + product.name);
11 System.out.println("Price : " + product.price);
12 System.out.println("Stock : " + product.stock);
13 }
14}Output:
Name : null
Price : 0.0
Stock : 0
The JVM initialises all fields to their type defaults before the constructor body runs — reference types become null, numeric types become 0, booleans become false. The default constructor does nothing beyond allowing this initialisation to happen.
Once you write any constructor in a class — even a parameterised one — the compiler stops generating the default constructor. If you still need a no-arg constructor alongside the parameterised one, you must write it explicitly.
No-Argument Constructor (Custom)
A no-arg constructor is one you write yourself with no parameters. Unlike the compiler-generated default, yours can set meaningful initial values.
1// File: GuestSession.java
2
3public class GuestSession {
4
5 private final String sessionId;
6 private String userType;
7 private int pageViewCount;
8 private boolean isActive;
9
10 // Custom no-arg constructor — sets up a meaningful default state
11 public GuestSession() {
12 this.sessionId = "GUEST-" + System.currentTimeMillis();
13 this.userType = "ANONYMOUS";
14 this.pageViewCount = 0;
15 this.isActive = true;
16 }
17
18 public String getSessionId() { return sessionId; }
19 public String getUserType() { return userType; }
20 public int getPageViewCount(){ return pageViewCount; }
21 public boolean isActive() { return isActive; }
22
23 public void recordPageView() { pageViewCount++; }
24}1// File: GuestSessionDemo.java
2
3public class GuestSessionDemo {
4
5 public static void main(String[] args) {
6
7 GuestSession session = new GuestSession();
8
9 System.out.println("Session ID : " + session.getSessionId());
10 System.out.println("User type : " + session.getUserType());
11 System.out.println("Active : " + session.isActive());
12
13 session.recordPageView();
14 session.recordPageView();
15 System.out.println("Page views : " + session.getPageViewCount());
16 }
17}Output:
Session ID : GUEST-1704067200000
User type : ANONYMOUS
Active : true
Page views : 2
The session ID is generated from the current timestamp at construction time — every GuestSession object gets a unique ID automatically. No caller needs to supply it. This is the power of the custom no-arg constructor: it enforces a well-defined starting state without requiring the caller to know or supply the details.
Parameterised Constructor
A parameterised constructor accepts arguments from the caller to set the object's initial state. This is the most commonly written constructor form in production Java.
1// File: DeliveryAddress.java
2
3public class DeliveryAddress {
4
5 private final String recipientName;
6 private final String streetAddress;
7 private final String city;
8 private final String pinCode;
9 private final String state;
10
11 public DeliveryAddress(String recipientName, String streetAddress,
12 String city, String pinCode, String state) {
13 this.recipientName = recipientName;
14 this.streetAddress = streetAddress;
15 this.city = city;
16 this.pinCode = pinCode;
17 this.state = state;
18 }
19
20 public String getFormattedAddress() {
21 return recipientName + "\n"
22 + streetAddress + "\n"
23 + city + " - " + pinCode + "\n"
24 + state;
25 }
26}1// File: DeliveryAddressDemo.java
2
3public class DeliveryAddressDemo {
4
5 public static void main(String[] args) {
6
7 DeliveryAddress addr = new DeliveryAddress(
8 "Priya Sharma",
9 "Flat 4B, Orchid Residency, MG Road",
10 "Bengaluru",
11 "560001",
12 "Karnataka"
13 );
14
15 System.out.println("=== Delivery Address ===");
16 System.out.println(addr.getFormattedAddress());
17 }
18}Output:
=== Delivery Address ===
Priya Sharma
Flat 4B, Orchid Residency, MG Road
Bengaluru - 560001
Karnataka
All fields are final — once set in the constructor, they cannot be changed. This makes DeliveryAddress immutable: once created, no code can accidentally overwrite a delivery destination. The final modifier on fields, combined with a parameterised constructor and no setters, is the standard pattern for immutable value objects in Java.
Copy Constructor
A copy constructor creates a new object by copying the state of an existing object of the same class. Java does not generate one automatically — you must write it explicitly.
1// File: CartItem.java
2
3public class CartItem {
4
5 private String productSku;
6 private String productName;
7 private int quantity;
8 private double unitPrice;
9
10 // Parameterised constructor
11 public CartItem(String productSku, String productName,
12 int quantity, double unitPrice) {
13 this.productSku = productSku;
14 this.productName = productName;
15 this.quantity = quantity;
16 this.unitPrice = unitPrice;
17 }
18
19 // Copy constructor — creates an independent copy of another CartItem
20 public CartItem(CartItem other) {
21 this.productSku = other.productSku;
22 this.productName = other.productName;
23 this.quantity = other.quantity;
24 this.unitPrice = other.unitPrice;
25 }
26
27 public void setQuantity(int quantity) { this.quantity = quantity; }
28 public int getQuantity() { return quantity; }
29 public String getProductName() { return productName; }
30 public double getLineTotal() { return quantity * unitPrice; }
31
32 public String getSummary() {
33 return productName + " x" + quantity + " = Rs." + getLineTotal();
34 }
35}1// File: CartItemDemo.java
2
3public class CartItemDemo {
4
5 public static void main(String[] args) {
6
7 CartItem originalItem = new CartItem("SKU-101", "Mechanical Keyboard", 1, 4599.0);
8
9 // Copy constructor creates a genuinely independent object
10 CartItem savedItem = new CartItem(originalItem);
11
12 // Modifying the original does not affect the copy
13 originalItem.setQuantity(3);
14
15 System.out.println("Original : " + originalItem.getSummary());
16 System.out.println("Saved : " + savedItem.getSummary());
17 System.out.println("Same object? " + (originalItem == savedItem));
18 }
19}Output:
Original : Mechanical Keyboard x3 = Rs.13797.0
Saved : Mechanical Keyboard x1 = Rs.4599.0
Same object? false
savedItem is a completely independent object. Changing quantity on originalItem has zero effect on savedItem. This is the critical difference between a copy constructor and simple assignment — CartItem savedItem = originalItem would create two references to the same object, not two separate objects.
Constructor Overloading
A class can have multiple constructors as long as each has a different parameter list. Java uses the argument types and count to decide which constructor to call.
1// File: Notification.java
2
3public class Notification {
4
5 private final String title;
6 private final String message;
7 private final String recipientId;
8 private final String channel;
9 private final int priority;
10
11 // Constructor 1 — minimal: just title and message, defaults applied
12 public Notification(String title, String message) {
13 this(title, message, "BROADCAST", "PUSH", 3);
14 }
15
16 // Constructor 2 — with recipient
17 public Notification(String title, String message, String recipientId) {
18 this(title, message, recipientId, "PUSH", 3);
19 }
20
21 // Constructor 3 — full control
22 public Notification(String title, String message,
23 String recipientId, String channel, int priority) {
24 this.title = title;
25 this.message = message;
26 this.recipientId = recipientId;
27 this.channel = channel;
28 this.priority = priority;
29 }
30
31 public String getSummary() {
32 return "[" + channel + "] P" + priority + " | To: " + recipientId
33 + " | " + title + ": " + message;
34 }
35}1// File: NotificationDemo.java
2
3public class NotificationDemo {
4
5 public static void main(String[] args) {
6
7 Notification broadcast = new Notification(
8 "Maintenance Alert",
9 "Scheduled downtime at 2 AM."
10 );
11
12 Notification personal = new Notification(
13 "Order Shipped",
14 "Your order ORD-4521 is on the way.",
15 "USER-9876"
16 );
17
18 Notification urgent = new Notification(
19 "Payment Failed",
20 "Retry your payment for ORD-4522.",
21 "USER-9876", "SMS", 1
22 );
23
24 System.out.println(broadcast.getSummary());
25 System.out.println(personal.getSummary());
26 System.out.println(urgent.getSummary());
27 }
28}Output:
[PUSH] P3 | To: BROADCAST | Maintenance Alert: Scheduled downtime at 2 AM.
[PUSH] P3 | To: USER-9876 | Order Shipped: Your order ORD-4521 is on the way.
[SMS] P1 | To: USER-9876 | Payment Failed: Retry your payment for ORD-4522.
Each simpler constructor delegates to the most complete one using this(...). This is constructor chaining — covered next.
Constructor Chaining with this()
Constructor chaining is when one constructor calls another constructor in the same class using this(). The this() call must be the first statement in the constructor body — the compiler enforces this.
The pattern avoids duplicating initialisation logic across overloaded constructors. Only the most complete constructor does the actual field assignment — all others delegate to it.
Constructor 1 — minimal args
|
+---> this(arg1, arg2, default3, default4)
|
Constructor 2 — partial args
|
+---> this(arg1, arg2, arg3, default4)
|
Constructor 3 — all args
|
FIELD ASSIGNMENTS happen here
This ensures every field is always initialised through a single, controlled path. A mistake that appears often in fresher pull requests is duplicating field assignments across multiple constructors — when a new field is added, it must be added in every constructor separately, and one is inevitably missed.
Constructor Chaining with super()
When a class extends another, its constructor must call the parent's constructor using super(). Like this(), it must be the first statement. If you do not write super() explicitly, the compiler inserts super() automatically — calling the parent's no-arg constructor. If the parent has no no-arg constructor, the compiler will fail and you must call the correct parent constructor manually.
1// File: Vehicle.java
2
3public class Vehicle {
4
5 private final String registrationNumber;
6 private final String vehicleType;
7 private final int seatingCapacity;
8
9 public Vehicle(String registrationNumber, String vehicleType, int seatingCapacity) {
10 this.registrationNumber = registrationNumber;
11 this.vehicleType = vehicleType;
12 this.seatingCapacity = seatingCapacity;
13 }
14
15 public String getRegistrationNumber() { return registrationNumber; }
16 public String getVehicleType() { return vehicleType; }
17 public int getSeatingCapacity() { return seatingCapacity; }
18
19 public String getBaseSummary() {
20 return vehicleType + " | Reg: " + registrationNumber
21 + " | Seats: " + seatingCapacity;
22 }
23}1// File: ElectricBus.java
2
3public class ElectricBus extends Vehicle {
4
5 private final int batteryCapacityKwh;
6 private final double rangePerChargeKm;
7
8 public ElectricBus(String registrationNumber, int seatingCapacity,
9 int batteryCapacityKwh, double rangePerChargeKm) {
10 // super() must be the first statement — initialises parent fields
11 super(registrationNumber, "Electric Bus", seatingCapacity);
12 this.batteryCapacityKwh = batteryCapacityKwh;
13 this.rangePerChargeKm = rangePerChargeKm;
14 }
15
16 public String getFullSummary() {
17 return getBaseSummary()
18 + " | Battery: " + batteryCapacityKwh + " kWh"
19 + " | Range: " + rangePerChargeKm + " km/charge";
20 }
21}1// File: ElectricBusDemo.java
2
3public class ElectricBusDemo {
4
5 public static void main(String[] args) {
6
7 ElectricBus bus = new ElectricBus("MH01AB1234", 42, 250, 300.0);
8
9 System.out.println(bus.getFullSummary());
10 }
11}Output:
Electric Bus | Reg: MH01AB1234 | Seats: 42 | Battery: 250 kWh | Range: 300.0 km/charge
The ElectricBus constructor first calls super() to initialise the Vehicle fields, then sets its own EV-specific fields. Without the super() call, the parent's registrationNumber, vehicleType, and seatingCapacity fields would never be set, and getBaseSummary() would return null values.
this() vs super() — Key Differences
| Aspect | this() | super() |
|---|---|---|
| Purpose | Calls another constructor in the same class | Calls a constructor in the parent class |
| Position | Must be the first statement in the constructor | Must be the first statement in the constructor |
| Can they coexist | No — only one of this() or super() can be the first statement | No — same rule applies |
| Generated by compiler | No | Yes — compiler inserts super() if you omit it |
| Use case | Constructor chaining to avoid duplication | Initialising inherited fields from parent |
Real-World Example — Order Creation System
The Business Problem
You are building the order management service for a hyperlocal delivery platform — similar to what Dunzo or Swiggy runs for its order pipeline. Orders are created in different contexts: sometimes a full order with all details from the app, sometimes a minimal guest order from the web, and sometimes a reorder copied from a previous order. All three scenarios require a different constructor form but must produce a consistently valid Order object.
Implementation
1// File: OrderConfig.java
2
3public final class OrderConfig {
4
5 public static final String DEFAULT_CHANNEL = "APP";
6 public static final String STATUS_PENDING = "PENDING";
7
8 private OrderConfig() {}
9}1// File: Order.java
2
3import java.time.LocalDateTime;
4import java.time.format.DateTimeFormatter;
5
6public class Order {
7
8 private static int orderSequence = 1000;
9
10 private final String orderId;
11 private final String customerId;
12 private final String deliveryAddress;
13 private final double orderTotal;
14 private final String channel;
15 private String status;
16 private final LocalDateTime createdAt;
17
18 // Constructor 1 — full order from the app
19 public Order(String customerId, String deliveryAddress,
20 double orderTotal, String channel) {
21 this.orderId = "ORD-" + (++orderSequence);
22 this.customerId = customerId;
23 this.deliveryAddress = deliveryAddress;
24 this.orderTotal = orderTotal;
25 this.channel = channel;
26 this.status = OrderConfig.STATUS_PENDING;
27 this.createdAt = LocalDateTime.now();
28 }
29
30 // Constructor 2 — guest order, channel defaults to APP
31 public Order(String customerId, String deliveryAddress, double orderTotal) {
32 this(customerId, deliveryAddress, orderTotal, OrderConfig.DEFAULT_CHANNEL);
33 }
34
35 // Copy constructor — reorder from an existing order
36 public Order(Order previousOrder, String newDeliveryAddress) {
37 this(previousOrder.customerId, newDeliveryAddress,
38 previousOrder.orderTotal, previousOrder.channel);
39 }
40
41 public String getOrderId() { return orderId; }
42 public String getStatus() { return status; }
43
44 public void updateStatus(String newStatus) {
45 this.status = newStatus;
46 }
47
48 public String getSummary() {
49 DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
50 return orderId + " | Customer: " + customerId
51 + " | Rs." + orderTotal + " | Channel: " + channel
52 + " | Status: " + status
53 + " | Created: " + createdAt.format(fmt);
54 }
55}1// File: OrderDemo.java
2
3public class OrderDemo {
4
5 public static void main(String[] args) {
6
7 // Full app order
8 Order appOrder = new Order(
9 "CUST-001",
10 "12 MG Road, Bengaluru",
11 549.0,
12 "APP"
13 );
14
15 // Guest order — channel defaults to APP
16 Order guestOrder = new Order(
17 "GUEST-002",
18 "7 Park Street, Mumbai",
19 320.0
20 );
21
22 // Reorder from previous order, new delivery address
23 Order reOrder = new Order(appOrder, "45 Koramangala, Bengaluru");
24
25 System.out.println(appOrder.getSummary());
26 System.out.println(guestOrder.getSummary());
27 System.out.println(reOrder.getSummary());
28 }
29}Output:
ORD-1001 | Customer: CUST-001 | Rs.549.0 | Channel: APP | Status: PENDING | Created: 15-01-2024 10:30
ORD-1002 | Customer: GUEST-002 | Rs.320.0 | Channel: APP | Status: PENDING | Created: 15-01-2024 10:30
ORD-1003 | Customer: CUST-001 | Rs.549.0 | Channel: APP | Status: PENDING | Created: 15-01-2024 10:30
Three different constructors, three creation contexts, all producing valid Order objects. The two simpler constructors delegate to the full constructor through this() — field assignment happens in exactly one place. When a new field is added to Order, only the full constructor changes — the simpler constructors automatically pick it up through chaining.
Constructors vs Methods — Key Differences
| Aspect | Constructor | Method |
|---|---|---|
| Name | Must match the class name exactly | Any valid identifier |
| Return type | None — not even void | Must declare a return type |
| Called by | new keyword (automatically) | Explicitly by name |
| Purpose | Initialise a new object | Perform an operation on an existing object |
| Inherited | Not inherited by subclasses | Inherited (unless private) |
| Overriding | Cannot be overridden | Can be overridden in subclasses |
this() / super() | Can call other constructors | Cannot call constructors with this() |
Best Practices
Always validate constructor arguments
The constructor is the object's birth — if invalid data enters at construction, the object is corrupted from the start. Validate all arguments before assigning them to fields. Throw IllegalArgumentException for invalid inputs rather than silently assigning them.
1public Product(String name, double price, int stock) {
2 if (name == null || name.isBlank()) throw new IllegalArgumentException("Name required.");
3 if (price < 0) throw new IllegalArgumentException("Price cannot be negative.");
4 if (stock < 0) throw new IllegalArgumentException("Stock cannot be negative.");
5 this.name = name;
6 this.price = price;
7 this.stock = stock;
8}Use constructor chaining to avoid duplication
If multiple constructors share the same field assignments, chain the simpler ones to the complete one using this(). Field assignment logic in one place means one change location when requirements evolve.
Declare fields final when they should not change after construction
For fields that are set in the constructor and should never change — IDs, immutable values, configuration — declare them final. The compiler then guarantees they are assigned exactly once, catching omissions at compile time.
Prefer constructor injection over setter injection for required fields
Fields that an object cannot function without should be required constructor parameters — not optional setters. This makes it impossible to create an invalid object where required data is missing. Setters are appropriate only for optional or changeable fields.
Common Mistakes
Mistake 1 — Writing a Parameterised Constructor and Forgetting to Add No-Arg
1public class UserProfile {
2
3 private String username;
4 private String email;
5
6 // Only a parameterised constructor — compiler stops generating the default
7 public UserProfile(String username, String email) {
8 this.username = username;
9 this.email = email;
10 }
11}
12
13// This now fails to compile — no no-arg constructor exists
14// UserProfile profile = new UserProfile();The moment you write any constructor, the compiler's generated default disappears. If frameworks like Hibernate, Jackson, or Spring need to create objects with no arguments (for deserialisation or bean creation), the missing no-arg constructor causes a runtime failure. The fix is to explicitly add public UserProfile() {} alongside the parameterised one.
Mistake 2 — this() or super() Is Not the First Statement
1public class OrderItem {
2
3 private String sku;
4 private int qty;
5
6 public OrderItem(String sku) {
7 System.out.println("Creating item..."); // compile error — this() must be first
8 this(sku, 1);
9 }
10
11 public OrderItem(String sku, int qty) {
12 this.sku = sku;
13 this.qty = qty;
14 }
15}Compile error: call to this must be first statement in constructor
Neither this() nor super() can be preceded by any other statement in the constructor. The compiler enforces this to ensure parent initialisation always happens before anything else runs. Move any logic you need before the chain into the constructor being delegated to — not before the this() call.
Mistake 3 — Duplicating Field Assignment Across Constructors
1// Wrong — same assignment appears in two constructors
2public class Invoice {
3
4 private String invoiceId;
5 private String customerId;
6 private double amount;
7 private String currency;
8
9 public Invoice(String invoiceId, String customerId, double amount) {
10 this.invoiceId = invoiceId; // duplicated
11 this.customerId = customerId; // duplicated
12 this.amount = amount; // duplicated
13 this.currency = "INR"; // duplicated
14 }
15
16 public Invoice(String invoiceId, String customerId, double amount, String currency) {
17 this.invoiceId = invoiceId; // same code again
18 this.customerId = customerId;
19 this.amount = amount;
20 this.currency = currency;
21 }
22}Adding a new field to Invoice requires updating both constructors. One will inevitably be missed. Use this() from the simpler constructor to delegate to the complete one — field assignment lives in one place only.
Mistake 4 — Calling Overridable Methods from a Constructor
1public class Base {
2
3 public Base() {
4 initialise(); // calls an overridable method during construction — dangerous
5 }
6
7 public void initialise() {
8 System.out.println("Base initialise");
9 }
10}
11
12public class Child extends Base {
13
14 private String data;
15
16 public Child(String data) {
17 super(); // calls Base(), which calls initialise()
18 this.data = data;
19 }
20
21 @Override
22 public void initialise() {
23 // At this point, Child.data has NOT been assigned yet — it is still null
24 System.out.println("Child initialise: " + data);
25 }
26}When Base() calls initialise(), Java dispatches to the Child override because the runtime type is Child. But Child.data has not been assigned yet — the super() call runs before the Child constructor body. The result is null printed where a value was expected. Never call overridable methods from constructors.
Interview Questions
Q1. What is a constructor in Java and how is it different from a method?
A constructor is a special block of code that runs automatically when an object is created with new. It shares the class name, has no return type (not even void), and cannot be called directly. A method has an arbitrary name, must declare a return type, and is called explicitly. Constructors initialise object state at birth; methods perform operations on an existing object's state. Constructors are not inherited by subclasses; methods are.
Q2. What is the difference between a default constructor and a no-arg constructor?
A default constructor is generated by the compiler when no constructor is written in the class — it has no parameters and an empty body. A no-arg constructor is one you write explicitly with no parameters — it can contain any initialisation logic you choose. The moment you write any constructor, the compiler stops generating the default. If you need both a no-arg and a parameterised constructor, you must write both explicitly.
Q3. What is constructor chaining in Java?
Constructor chaining is when one constructor delegates to another using this() within the same class, or super() to call the parent class constructor. this() and super() must both appear as the first statement in a constructor — you cannot have both, and you cannot precede either with any other code. Constructor chaining ensures field assignment logic lives in one place, so adding a field requires changing only the delegated-to constructor.
Q4. What happens if you do not write a super() call in a subclass constructor?
The compiler automatically inserts super() — a call to the parent's no-argument constructor — as the first statement. If the parent class has no no-argument constructor (only parameterised ones), the compiler fails and forces you to write an explicit super(args) call with the correct arguments. This is a common compilation error when extending a class that has only parameterised constructors.
Q5. What is the difference between this() and super() in a constructor?
this() calls another constructor within the same class — used for constructor chaining to avoid duplicating field assignment logic. super() calls a constructor in the parent class — used to initialise inherited fields. Both must be the first statement in the constructor, meaning only one can appear in any given constructor. Both are compile-time constructs that determine the constructor call chain before the object's body code runs.
Q6. Why should you avoid calling overridable methods inside a constructor?
When a constructor calls an overridable method, Java dispatches to the subclass's override — even though the subclass constructor has not run yet. The subclass's fields are still at their default values (null, 0, false). This causes the overriding method to operate on uninitialised state, producing NullPointerException or incorrect behaviour that is extremely difficult to debug. Use private or final methods if you must call methods during construction, since those cannot be overridden.
FAQs
Can a constructor return a value in Java?
No. Constructors have no return type — not even void. Attempting to declare a return type on a constructor turns it into a regular method with the same name as the class, which compiles but is never called by new. A constructor communicates results through the object it creates and by throwing exceptions for invalid inputs.
Can a constructor be private in Java?
Yes. A private constructor prevents any code outside the class from instantiating it directly. This pattern is used for singleton classes (where only one instance should exist), utility classes (where no instance should ever be created), and factory method patterns where object creation is controlled through a static method.
Can you have two constructors with the same parameter types in Java?
No. Java distinguishes constructors by the number, type, and order of their parameters — the same rules as method overloading. Two constructors with identical parameter lists are a compile-time error regardless of parameter names.
What is a copy constructor in Java?
A copy constructor creates a new object by copying the field values of an existing object of the same class. It takes one parameter of the same class type. Java does not generate one automatically — you write it explicitly. It creates a genuinely independent object, unlike object assignment which creates two references to the same object.
Is it possible to call a constructor inside another constructor in Java?
Yes — this is constructor chaining. Use this() to call another constructor in the same class, or super() to call a parent constructor. Both must be the first statement in the constructor body. This pattern avoids repeating field assignment logic across multiple constructors.
Why does Java not allow constructors to be inherited?
Constructors are tied to the specific class they belong to — their purpose is to initialise fields declared in that class. If a subclass could inherit a parent constructor, it would initialise only the parent's fields and skip the subclass's own fields, producing an incompletely initialised object. Java prevents this by requiring each class to define its own constructors while using super() to delegate parent-field initialisation explicitly.
Summary
Constructors are the controlled entry point for every object in Java. Default, no-arg, parameterised, and copy constructors each solve a different object creation scenario — understanding when to use each is what interviewers probe at both service-based and product-based companies.
Constructor chaining through this() is the most important production pattern: it ensures field assignment happens in one place and protects against the "missing field when a new one is added" class of bugs. The super() call is not optional when parent classes have no no-arg constructor — the compiler will tell you clearly when it is missing.
For interviews, be ready to explain the difference between a compiler-generated default and a custom no-arg constructor, demonstrate constructor chaining with this(), and explain why overridable methods must not be called inside constructors. These three points cover the depth that both recall-based questions and design-based discussions test on this topic.
What to Read Next
| Topic | Link |
|---|---|
| How access modifiers control what is visible inside and outside a class | Access Modifiers → |
| How encapsulation uses private fields and constructors to protect object state | Encapsulation → |
| How inheritance uses super() to chain parent constructors | Inheritance → |