1. Constructor overloading syntax
In real life, it’s rare that all objects are created the same way. Imagine a Person class (Human). Sometimes we only need to create a person when we know their name. Sometimes — name and age. And sometimes — we don’t know anything at all, so let everything be default. It would be strange to force a user of the class to always specify every parameter, even when they don’t need them.
Constructor overloading is a way to give a class user a choice: which parameters they want to specify when creating an object, and which to leave at their default values. This makes a class flexible and convenient to use.
Analogy:
In a design bureau, cars are built. Some customers order the base trim (no air conditioning, just a steering wheel and wheels), others want “luxury” (heated seats, Wi‑Fi, and self-driving). But the car is still the same class—just different ways to assemble it!
Overloading is when multiple constructors are declared in one class, but with different parameters (different count, types, or order). They are all named the same as the class and have no return type.
Example: A class with overloaded constructors
public class Person {
String name;
int age;
// No-arg constructor (default)
public Person() {
this.name = "Unknown";
this.age = 0;
}
// Constructor with one parameter
public Person(String name) {
this.name = name;
this.age = 0;
}
// Constructor with two parameters
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
Now we can create objects in different ways:
Person p1 = new Person(); // name = "Unknown", age = 0
Person p2 = new Person("Bill"); // name = "Bill", age = 0
Person p3 = new Person("Pete", 25); // name = "Pete", age = 25
How does Java know which constructor to use?
Java looks at the number and types of arguments you pass after new. If you write new Person("Bill"), the compiler searches for a constructor with one parameter of type String. If you write new Person("Pete", 25), it needs a constructor with parameters String and int.
2. Calling one constructor from another: this(...)
Sometimes, when overloading constructors, you encounter repeating code. For example, you want all constructors to always set the name, and the age to be zero if not provided. To avoid duplicating the same logic in every constructor, you can call one constructor from another using the keyword this(...).
Example
public class Person {
String name;
int age;
// Constructor with two parameters
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Constructor with one parameter calls another constructor
public Person(String name) {
this(name, 0); // calls Person(String name, int age)
}
// No-arg constructor calls another constructor
public Person() {
this("Unknown", 0);
}
}
public Person(String name) {
this(name, 0); // calls Person(String, int)
}
Important rule: A call to another constructor via this(...) must be the first statement in the constructor!
Why is this useful?
- Reduces code duplication.
- If you decide to change initialization logic (for example, adjust a default value), you only need to change it in one place.
- The code becomes cleaner and easier to maintain.
3. Practical examples: overloading in a real class
Suppose we have an Account class—a bank account. Sometimes we only know the owner’s name, sometimes we want to specify the initial balance right away, and sometimes also the currency.
Example of a class with overloaded constructors
public class Account {
String owner;
double balance;
String currency;
// Constructor with three parameters
public Account(String owner, double balance, String currency) {
this.owner = owner;
this.balance = balance;
this.currency = currency;
}
// Constructor with two parameters (default currency - "EUR")
public Account(String owner, double balance) {
this(owner, balance, "EUR");
}
// Constructor with one parameter (balance = 0, currency = "EUR")
public Account(String owner) {
this(owner, 0.0, "EUR");
}
// No-arg constructor (owner - "Unknown", balance = 0, currency = "EUR")
public Account() {
this("Unknown", 0.0, "EUR");
}
public void printInfo() {
System.out.println(owner + ": " + balance + " " + currency);
}
}
Usage
public class Main {
public static void main(String[] args) {
Account acc1 = new Account("John", 1000, "USD");
Account acc2 = new Account("Mary", 500);
Account acc3 = new Account("Peter");
Account acc4 = new Account();
acc1.printInfo(); // John: 1000.0 USD
acc2.printInfo(); // Mary: 500.0 EUR
acc3.printInfo(); // Peter: 0.0 EUR
acc4.printInfo(); // Unknown: 0.0 EUR
}
}
Why is this convenient?
- You can create objects with varying levels of detail.
- No need to specify all parameters every time (especially if they are often the same).
- It’s easy to extend the class: if a new parameter appears, you can add another constructor.
4. Common mistakes when overloading constructors
Error #1: Confusing parameter types and order.
If you have two constructors — Person(String name, int age) and Person(int age, String name) — the compiler will distinguish them, but it can be extremely confusing for users of the class. It’s better to avoid such situations.
Error #2: Missing no-arg constructor.
If you declare only constructors with parameters and then try to create an object with no arguments, you’ll get a compilation error. Always add a no-arg constructor if it’s needed.
Error #3: Trying to call another constructor not as the first statement.
A this(...) call must always be the first statement in a constructor. If you write anything before it, you’ll get a compilation error.
Error #4: Constructor call loops.
If a constructor calls itself (directly or through a chain), it will lead to a compilation error due to infinite recursion.
Error #5: Uninitialized fields.
If you forget to initialize a field in a constructor (or in a call chain), the object may end up in an incorrect state. Make sure all fields have meaningful values after the object is created.
GO TO FULL VERSION