Constructors in Java
In Java, a constructor is a unique kind of method that is essential to an object’s existence. Setting an object’s initialisation right after creation is its main purpose. A constructor, in contrast to conventional methods, has no return type and is named after its class. It is automatically called anytime the new keyword is used to create an object of its class.
Why Constructors Are Used
A constructor’s primary function is to guarantee that an object is legitimate and useable when it is first formed. Constructors give the programmer a quick and easy way to complete all setup tasks without having to manually configure each instance variable after constructing an object. Unpredictable program behaviour could result from fields being left uninitialised, which is something that our automatic initialisation helps avoid. As the “building instructions” for an object, constructors establish its basic properties from the very beginning.

Default Constructor
Java classes all have constructors. The Java compiler automatically offers a default constructor for your class if you don’t provide any explicitly. This default constructor does not carry out any special initialisation and is parameter-less, often known as a “no-argument constructor.” Instead, it automatically initialises all instance variables to their default values: 0
or 0.0
for numeric types, '\u0000'
for char
, false
for boolean
, and null
for all reference types.
Consider a basic class without a defined constructor:
class MySimpleClass {
int value; // Will default to 0
String name; // Will default to null
boolean active; // Will default to false
}
class DefaultConstructorDemo {
public static void main(String args[]) {
MySimpleClass obj = new MySimpleClass(); // Default constructor is implicitly called
System.out.println("obj.value: " + obj.value);
System.out.println("obj.name: " + obj.name);
System.out.println("obj.active: " + obj.active);
}
}
Code Output:
obj.value: 0
obj.name: null
obj.active: false
It is vital to remember that the compiler will no longer automatically offer the default constructor after you declare any constructor of your own. You must specify a no-argument constructor explicitly if you still require one after declaring others.
Parameterised Constructors
Although the default constructor is adequate for straightforward situations, the majority of real-world classes require initialisation with particular values. This is done by using parameterised constructors, which take one or more arguments to set the initial state of the object.
Here’s an example using a MyClass
with a parameterised constructor:
class MyClass {
int x;
// Parameterised constructor
MyClass(int i) {
x = i;
}
}
class ConsDemo {
public static void main(String args[]) {
MyClass t1 = new MyClass(10); // Calls constructor with 10
MyClass t2 = new MyClass(88); // Calls constructor with 88
System.out.println("t1.x: " + t1.x);
System.out.println("t2.x: " + t2.x);
}
}
Code Output:
t1.x: 10
t2.x: 88
This illustrates how different values can be supplied to each object upon creation, enabling a variety of object instances.
Constructor Overloading
Like methods, constructors are susceptible to overloading. This implies that several constructors with the same name can exist in a class as long as their parameter lists (also known as “signatures”) differ. The number, kind, and arrangement of the arguments of an overloaded constructor determine how the Java compiler distinguishes between them.
Flexibility in object formation is achieved via overloading constructors. You can provide an object a constructor that requires no arguments for default settings, one that requires numerous arguments for complete customisation, or one that requires minimal setup.
Let’s illustrate constructor overloading using a MyClass
example with several constructors:
class MyClass {
int x;
// 1. No-argument constructor
MyClass() {
System.out.println("Inside MyClass().");
x = 0;
}
// 2. Constructor with one int parameter
MyClass(int i) {
System.out.println("Inside MyClass(int).");
x = i;
}
// 3. Constructor with one double parameter
MyClass(double d) {
System.out.println("Inside MyClass(double).");
x = (int) d; // Casts double to int
}
// 4. Constructor with two int parameters
MyClass(int i, int j) {
System.out.println("Inside MyClass(int, int).");
x = i * j;
}
}
class OverloadConsDemo {
public static void main(String args[]) {
// Create objects using various constructors
MyClass t1 = new MyClass(); // Calls MyClass()
MyClass t2 = new MyClass(88); // Calls MyClass(int)
MyClass t3 = new MyClass(17.23); // Calls MyClass(double)
MyClass t4 = new MyClass(2, 4); // Calls MyClass(int, int)
System.out.println("t1.x: " + t1.x);
System.out.println("t2.x: " + t2.x);
System.out.println("t3.x: " + t3.x);
System.out.println("t4.x: " + t4.x);
}
}
Code Output:
Inside MyClass().
Inside MyClass(int).
Inside MyClass(double).
Inside MyClass(int, int).
t1.x: 0
t2.x: 88
t3.x: 17
t4.x: 8
With the help of the arguments supplied during object instantiation, the compiler selects the right constructor, giving users a variety of alternatives for creating objects.
The keyword
The this
keyword in Java is a reference to the current object specifically, the object upon which a method or constructor was invoked. It can be used anywhere a reference to an object of the current class’s type is permitted.
One significant use of this
is to disambiguate instance variables from local variables or parameters when they share the same name. This enhances code clarity and prevents confusion.
Consider a constructor for an Employee
class:
public class Employee {
String name;
int age;
public Employee(String name, int age) {
// 'this.name' refers to the instance variable, 'name' refers to the parameter
this.name = name;
this.age = age;
System.out.println("Employee created: " + this.name + ", " + this.age + " years old.");
}
public static void main(String[] args) {
Employee emp1 = new Employee("Alice", 30);
}
}
Code Output:
Employee created: Alice, 30 years old.
To differentiate it from the name
parameter supplied to the constructor, this.name
here explicitly corresponds to the name
instance variable.
Constructor chaining is another strong use of the this
keyword, which is used to invoke another constructor within the same class using the syntax this(arg-list)
.
It is imperative that this(arg-list)
always be the first line executed inside the constructor; hence, a constructor cannot call both this()
and super()
(to call a parent class constructor) since both of these methods need to be the first statement.
A useful technique for minimising code duplication is constructor chaining, which enables a constructor to reuse initialisation logic written in a more general constructor of the same type.
Let’s modify our MyClass
example to demonstrate this()
for chaining constructors:
class MyClass {
int a;
int b;
// 1. Full constructor: initializes 'a' and 'b' individually
MyClass(int i, int j) {
a = i;
b = j;
System.out.println("Two-argument constructor: a=" + a + ", b=" + b);
}
// 2. Chained constructor: initializes 'a' and 'b' to the same value by calling the full constructor
MyClass(int i) {
this(i, i); // Calls MyClass(i, i)
System.out.println("One-argument constructor, called via chaining.");
}
// 3. Chained default constructor: gives 'a' and 'b' default values of 0 by calling the one-argument constructor
MyClass() {
this(0); // Calls MyClass(0)
System.out.println("No-argument constructor, called via chaining.");
}
}
class ThisConstructorDemo {
public static void main(String args[]) {
System.out.println("Creating mc1 (two args):");
MyClass mc1 = new MyClass(8, 12);
System.out.println("mc1.a: " + mc1.a + ", mc1.b: " + mc1.b);
System.out.println();
System.out.println("Creating mc2 (one arg):");
MyClass mc2 = new MyClass(5);
System.out.println("mc2.a: " + mc2.a + ", mc2.b: " + mc2.b);
System.out.println();
System.out.println("Creating mc3 (no args):");
MyClass mc3 = new MyClass();
System.out.println("mc3.a: " + mc3.a + ", mc3.b: " + mc3.b);
}
}
Code Output:
Creating mc1 (two args):
Two-argument constructor: a=8, b=12
mc1.a: 8, mc1.b: 12
Creating mc2 (one arg):
Two-argument constructor: a=5, b=5
One-argument constructor, called via chaining.
mc2.a: 5, mc2.b: 5
Creating mc3 (no args):
Two-argument constructor: a=0, b=0
One-argument constructor, called via chaining.
No-argument constructor, called via chaining.
mc3.a: 0, mc3.b: 0
The constructor call chain is evident in this output. Although this()
eliminates redundant code, it should be noted that constructors that use it may run a little more slowly because of the overhead of the call and return mechanism. Nevertheless, for complex initialisation logic, the advantages of cleaner, more manageable code frequently exceed this small performance issue.