Understanding Constructors and Their Purpose in Java
Course: Core Java Training
Topic: Understanding Constructors and Their Purpose
Course Link: Core Java Training Course
Demo Link: Register for a Course Demo
Website: JustAcademy
1. Introduction to Constructors in Java
A constructor is a special member of a Java class that is used to initialize a newly created object. It helps assign initial values to an object's fields and establish the object's initial state before the object is used by the program.
For example, when creating a student object, a constructor can initialize the student's name, roll number, and marks. Instead of creating an object with incomplete information and assigning each field separately, a constructor can accept the required values during object creation.
Constructors are an important part of object-oriented programming because they help ensure that objects are initialized consistently and make classes easier to use.
Learning Objectives
- Understand the meaning and purpose of constructors.
- Learn the syntax and rules for declaring constructors.
- Understand default constructors and no-argument constructors.
- Learn how to create parameterized constructors.
- Understand constructor overloading.
- Use the
this keyword in constructors.
- Learn constructor chaining using
this() and super().
- Understand constructor access modifiers and inheritance-related behavior.
- Identify common constructor mistakes and debugging techniques.
- Practice constructors through real-world Java examples.
2. What Is a Constructor?
A constructor is a class member that runs when an object is created using a class's instantiation process. It is primarily used to initialize the object's state.
A constructor has the same name as its class and does not declare a return type. Unlike an ordinary method, it cannot be called as a normal method on an already-created object.
Basic Syntax
class ClassName {
ClassName() {
// Initialization statements
}
}
Example: Simple Constructor
class Student {
String name;
int age;
Student() {
name = "Aarav";
age = 20;
}
void displayDetails() {
System.out.println("Name: " + name);
System.out.println("Age: " + age);
}
}
public class ConstructorExample {
public static void main(String[] args) {
Student student = new Student();
student.displayDetails();
}
}
Output
Name: Aarav
Age: 20
When new Student() creates the object, the constructor initializes the name and age fields. The displayDetails() method then displays those values.
3. Purpose of Constructors in Java
Constructors help initialize objects into a known and usable state. They can also validate input, select initial configuration, and prevent objects from being created with invalid data.
Main Purposes
- Initialize fields: Assign initial values to an object's properties.
- Accept required data: Receive values when an object is created.
- Maintain consistency: Ensure objects follow a predictable initialization process.
- Validate input: Reject invalid values before an object is used.
- Reduce repeated code: Centralize initialization logic rather than repeating assignments throughout the application.
- Support multiple creation options: Provide different constructors for different valid ways to create an object.
- Initialize inherited state: Coordinate initialization with superclass constructors when inheritance is used.
Example: Initializing an Employee
class Employee {
String name;
double salary;
Employee(String employeeName, double employeeSalary) {
name = employeeName;
salary = employeeSalary;
}
void display() {
System.out.println("Employee: " + name);
System.out.println("Salary: " + salary);
}
}
public class EmployeeDemo {
public static void main(String[] args) {
Employee employee = new Employee("Priya", 45000);
employee.display();
}
}
Output
Employee: Priya
Salary: 45000.0
The constructor receives the employee's name and salary and stores them in the object's fields. This allows the object to be initialized with different values whenever it is created.
4. Important Characteristics of Constructors
| Characteristic |
Explanation |
| Same name as class |
The constructor name must match the class name. |
| No return type |
A constructor does not declare a return type, including void. |
| Runs during construction |
It executes as part of the process of creating an object. |
| Can accept parameters |
Constructors can receive values to initialize fields. |
| Can be overloaded |
A class can define multiple constructors with different parameter lists. |
| Can use access modifiers |
Constructors can be declared public, protected, private, or package-private. |
| Cannot be inherited |
Constructors are not inherited by subclasses. |
| Cannot be overridden |
Constructor overriding does not exist in Java. |
| Can invoke another constructor |
this() and super() can be used for constructor chaining under Java's constructor invocation rules. |
5. Types of Constructors in Java
Constructors are commonly discussed using three categories: default constructors, no-argument constructors, and parameterized constructors. A default constructor is specifically the no-argument constructor supplied by the compiler when a class declares no constructor. An explicitly written no-argument constructor is not a compiler-provided default constructor.
5.1 Default Constructor
If a class does not declare any constructor, the Java compiler provides a default no-argument constructor. This constructor invokes the superclass's no-argument constructor and otherwise performs no additional initialization beyond the normal object initialization process.
class Car {
String brand;
int year;
}
public class DefaultConstructorDemo {
public static void main(String[] args) {
Car car = new Car();
System.out.println("Brand: " + car.brand);
System.out.println("Year: " + car.year);
}
}
Output
Brand: null
Year: 0
The class does not declare a constructor, so the compiler supplies a default no-argument constructor. The reference field brand receives the default value null, and the integer field year receives 0.
Important: If you declare any constructor yourself, Java does not automatically provide the default constructor.
5.2 Explicit No-Argument Constructor
A no-argument constructor is declared by the programmer and does not accept parameters. It can assign custom initial values to fields.
class Laptop {
String brand;
int ram;
Laptop() {
brand = "Lenovo";
ram = 16;
}
void display() {
System.out.println("Brand: " + brand);
System.out.println("RAM: " + ram + " GB");
}
}
public class NoArgumentConstructorDemo {
public static void main(String[] args) {
Laptop laptop = new Laptop();
laptop.display();
}
}
Output
Brand: Lenovo
RAM: 16 GB
This constructor initializes the laptop with predefined values. Because the constructor is explicitly declared, these initial values replace the normal default field values for this object.
5.3 Parameterized Constructor
A parameterized constructor accepts one or more parameters. It allows the caller to supply values when creating an object.
class Product {
String name;
double price;
Product(String productName, double productPrice) {
name = productName;
price = productPrice;
}
void display() {
System.out.println("Product: " + name);
System.out.println("Price: " + price);
}
}
public class ParameterizedConstructorDemo {
public static void main(String[] args) {
Product product1 = new Product("Keyboard", 1200);
Product product2 = new Product("Mouse", 700);
product1.display();
product2.display();
}
}
Output
Product: Keyboard
Price: 1200.0
Product: Mouse
Price: 700.0
The same constructor initializes two objects with different values. This makes the class reusable for different products.
6. Constructor vs Method
Constructors and methods are both members associated with classes, but they serve different purposes. A constructor initializes a new object, while a method performs an operation that can be invoked after an object has been created.
| Basis |
Constructor |
Method |
| Name |
Must match the class name. |
Can have any valid method name. |
| Return type |
Does not declare a return type. |
Must declare a return type, including void. |
| Purpose |
Initializes a new object. |
Performs an operation or calculates a result. |
| Invocation |
Invoked during object construction. |
Called explicitly when needed. |
| Inheritance |
Not inherited or overridden. |
Methods can be inherited and, where permitted, overridden. |
| Overloading |
Supported. |
Supported. |
| Example |
Student(String name) |
displayDetails() |
Example: Constructor and Method Together
class Circle {
double radius;
Circle(double radius) {
this.radius = radius;
}
double calculateArea() {
return Math.PI * radius * radius;
}
}
public class CircleDemo {
public static void main(String[] args) {
Circle circle = new Circle(5);
System.out.println("Area: " + circle.calculateArea());
}
}
Output
Area: 78.53981633974483
The constructor initializes the radius, and the method calculates the area whenever it is called.
7. Constructor Overloading
Constructor overloading means defining more than one constructor in the same class with different parameter lists. This allows objects to be created using different sets of initial values.
Constructors can be overloaded by changing the number, types, or order of their parameters. Changing only parameter names or access modifiers does not create a distinct overload.
Example: Multiple Constructors
class Student {
String name;
int age;
String course;
Student() {
this("Unknown", 18, "Not Assigned");
}
Student(String name, int age) {
this(name, age, "Core Java");
}
Student(String name, int age, String course) {
this.name = name;
this.age = age;
this.course = course;
}
void display() {
System.out.println(
name + " | " + age + " | " + course
);
}
}
public class ConstructorOverloadingDemo {
public static void main(String[] args) {
Student student1 = new Student();
Student student2 = new Student("Asha", 20);
Student student3 = new Student("Rahul", 22, "Python");
student1.display();
student2.display();
student3.display();
}
}
Output
Unknown | 18 | Not Assigned
Asha | 20 | Core Java
Rahul | 22 | Python
The class provides three ways to initialize a student. The shorter constructors reuse the main constructor through this(), reducing repeated initialization logic.
Benefits of Constructor Overloading
- Supports different ways of creating an object.
- Allows optional information to be supplied when needed.
- Provides convenient default values.
- Reduces repeated initialization statements when constructors delegate to a common constructor.
- Makes a class easier to use in different situations.
8. Understanding the this Keyword in Constructors
The this keyword refers to the current object in an instance context. In constructors, it is commonly used to distinguish fields from parameters with the same names.
Example Without this
class Employee {
String name;
double salary;
Employee(String employeeName, double employeeSalary) {
name = employeeName;
salary = employeeSalary;
}
}
This code works because the parameters have different names from the fields.
Example With this
class Employee {
String name;
double salary;
Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
void display() {
System.out.println(name + " earns " + salary);
}
}
public class ThisKeywordDemo {
public static void main(String[] args) {
Employee employee = new Employee("Neha", 50000);
employee.display();
}
}
Output
Neha earns 50000.0
Here, this.name refers to the object's field, while name refers to the constructor parameter. This naming pattern is common in Java programs.
9. Constructor Chaining Using this()
Constructor chaining means invoking one constructor from another constructor. The expression this() invokes another constructor in the same class.
In Java, an explicit constructor invocation using this() must be the first statement in the constructor body under the traditional constructor syntax. Modern Java also has flexible constructor-body rules in recent language versions, but introductory code should generally place this() first for clarity and compatibility.
Example
class Book {
String title;
double price;
String author;
Book() {
this("Untitled", 0.0, "Unknown");
}
Book(String title, double price) {
this(title, price, "Unknown");
}
Book(String title, double price, String author) {
this.title = title;
this.price = price;
this.author = author;
}
void display() {
System.out.println("Title: " + title);
System.out.println("Price: " + price);
System.out.println("Author: " + author);
}
}
public class ConstructorChainingDemo {
public static void main(String[] args) {
Book book1 = new Book();
Book book2 = new Book("Core Java", 550);
Book book3 = new Book("Effective Java", 700, "Joshua Bloch");
book1.display();
book2.display();
book3.display();
}
}
Output
Title: Untitled
Price: 0.0
Author: Unknown
Title: Core Java
Price: 550.0
Author: Unknown
Title: Effective Java
Price: 700.0
Author: Joshua Bloch
Constructor chaining centralizes initialization logic in one constructor. This makes future changes easier because the main initialization logic does not need to be repeated in every overload.
10. Calling a Superclass Constructor with super()
When a class extends another class, the superclass portion of an object must be initialized before the subclass constructor completes. The super() invocation calls a superclass constructor.
If a constructor does not explicitly invoke another constructor using this() or super(), Java normally inserts an implicit no-argument superclass constructor invocation when permitted. If the superclass has no accessible no-argument constructor, the subclass must explicitly invoke an appropriate superclass constructor.
Example
class Person {
String name;
Person(String name) {
this.name = name;
}
}
class Teacher extends Person {
String subject;
Teacher(String name, String subject) {
super(name);
this.subject = subject;
}
void display() {
System.out.println("Name: " + name);
System.out.println("Subject: " + subject);
}
}
public class SuperConstructorDemo {
public static void main(String[] args) {
Teacher teacher = new Teacher("Mr. Sharma", "Java");
teacher.display();
}
}
Output
Name: Mr. Sharma
Subject: Java
The Teacher constructor calls super(name) to initialize the inherited name field through the Person constructor. It then initializes the subject field.
11. Constructor Access Modifiers
Constructor access modifiers control where code can create objects using that constructor. The choice depends on how the class is intended to be used.
| Modifier |
General Accessibility |
Common Use |
public |
Accessible wherever the class itself is accessible. |
Classes intended to be instantiated by external code. |
protected |
Accessible within the same package and through inheritance under Java's protected-access rules. |
Supporting construction in package or subclass contexts. |
| Package-private |
Accessible only within the same package. |
Restricting object creation to a package. |
private |
Accessible within the declaring class's permitted context. |
Controlling object creation through class methods or factory methods. |
Example: Private Constructor
class AppConfig {
private static final AppConfig INSTANCE = new AppConfig();
private AppConfig() {
System.out.println("Configuration initialized.");
}
public static AppConfig getInstance() {
return INSTANCE;
}
}
public class PrivateConstructorDemo {
public static void main(String[] args) {
AppConfig config = AppConfig.getInstance();
System.out.println(config != null);
}
}
Output
Configuration initialized.
true
The private constructor prevents ordinary code outside AppConfig from directly calling new AppConfig(). The public static method provides access to the instance created by the class. This is a simple singleton-style example; singleton design requires additional considerations in more complex applications.
12. Constructor Initialization Order
Understanding initialization order helps explain how Java objects receive their values. For a typical class instantiation, the process includes memory allocation, default initialization of fields, superclass initialization, instance field initializers and initialization blocks, and constructor bodies according to the inheritance and constructor-chaining rules.
For ordinary instance creation, the following concepts are especially important:
- Memory is allocated for the new object.
- Instance fields receive their default values.
- Superclass initialization and constructor execution take place in the required order.
- Instance field initializers and instance initialization blocks run as part of initialization.
- The applicable constructor body executes.
Example
class Demo {
int number = 10;
{
number = 20;
System.out.println("Instance block: " + number);
}
Demo() {
number = 30;
System.out.println("Constructor: " + number);
}
}
public class InitializationOrderDemo {
public static void main(String[] args) {
Demo demo = new Demo();
System.out.println("Final value: " + demo.number);
}
}
Output
Instance block: 20
Constructor: 30
Final value: 30
The field initializer assigns 10, then the instance initialization block changes it to 20, and finally the constructor changes it to 30.
13. Validation Inside Constructors
Constructors can validate supplied values before storing them. This is useful when a class should never represent an invalid state, such as a negative product price or an age below zero.
Example: Validating Product Data
class Product {
private final String name;
private final double price;
Product(String name, double price) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException(
"Product name cannot be empty."
);
}
if (price < 0) {
throw new IllegalArgumentException(
"Price cannot be negative."
);
}
this.name = name;
this.price = price;
}
void display() {
System.out.println("Product: " + name);
System.out.println("Price: " + price);
}
}
public class ProductValidationDemo {
public static void main(String[] args) {
Product product = new Product("Keyboard", 1500);
product.display();
}
}
Output
Product: Keyboard
Price: 1500.0
The constructor rejects an empty name or a negative price by throwing an IllegalArgumentException. This helps prevent invalid product objects from being successfully constructed.
14. Can Constructors Be Inherited or Overridden?
Constructors are not inherited by subclasses and cannot be overridden. A subclass declares its own constructors and can call a superclass constructor using super().
Example
class Animal {
Animal() {
System.out.println("Animal constructor");
}
}
class Dog extends Animal {
Dog() {
super();
System.out.println("Dog constructor");
}
}
public class InheritanceConstructorDemo {
public static void main(String[] args) {
Dog dog = new Dog();
}
}
Output
Animal constructor
Dog constructor
When a Dog object is created, the superclass constructor runs before the subclass constructor body completes. The Dog class does not inherit the Animal() constructor; it invokes it as part of its own construction process.
15. Common Constructor Errors
| Error |
Why It Is Incorrect |
Correct Approach |
| Adding a return type |
void Student() declares a method, not a constructor. |
Declare Student() without a return type. |
| Using a different name |
The declaration will not be recognized as a constructor. |
Match the constructor name to the class name. |
| Assuming a default constructor always exists |
Declaring another constructor prevents the compiler from supplying a default one. |
Declare a no-argument constructor explicitly if needed. |
Calling this() after another statement |
Traditional constructor invocation rules require it to be the first statement. |
Place this() first under the traditional syntax. |
| Calling an unavailable superclass constructor |
The subclass cannot invoke a constructor that is inaccessible or does not exist. |
Call a suitable accessible superclass constructor. |
| Creating an invalid object state |
Invalid values may lead to bugs later. |
Validate constructor parameters before assigning fields. |
| Repeating initialization logic |
Duplicated logic can become inconsistent. |
Use constructor chaining where appropriate. |
| Trying to override a constructor |
Constructors are not inherited and cannot be overridden. |
Declare a constructor in the subclass and use super() when needed. |
16. Best Practices for Writing Constructors
- Initialize required fields when an object is created.
- Use descriptive parameter names.
- Use
this.fieldName = fieldName when parameter names match field names.
- Validate important input values before storing them.
- Use constructor overloading when different initialization options are useful.
- Use
this() to reuse initialization logic instead of duplicating it.
- Use
super() when a subclass must invoke a particular superclass constructor.
- Keep constructors focused on initialization rather than performing unrelated operations.
- Use private constructors when object creation needs to be controlled by the class.
- Prefer immutable fields, such as
final fields, when values should not change after construction.
- Avoid performing slow network, database, or other external operations directly inside constructors when a separate initialization workflow would be more appropriate.
- Document non-obvious constructor requirements and validation rules.
17. Practical Project: Bank Account Initialization
Objective: Create a Java class that uses constructors to initialize bank account information and enforce basic validation rules.
Requirements
- Create a
BankAccount class.
- Include account holder name, account number, and balance fields.
- Use a parameterized constructor to initialize the account.
- Reject an empty account holder name and a negative starting balance.
- Provide a method to deposit money.
- Provide a method to display account details.
- Create multiple accounts with different initial values.
Sample Solution
class BankAccount {
private final String accountHolder;
private final String accountNumber;
private double balance;
BankAccount(
String accountHolder,
String accountNumber,
double initialBalance
) {
if (accountHolder == null || accountHolder.isBlank()) {
throw new IllegalArgumentException(
"Account holder name is required."
);
}
if (accountNumber == null || accountNumber.isBlank()) {
throw new IllegalArgumentException(
"Account number is required."
);
}
if (initialBalance < 0) {
throw new IllegalArgumentException(
"Initial balance cannot be negative."
);
}
this.accountHolder = accountHolder;
this.accountNumber = accountNumber;
this.balance = initialBalance;
}
void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException(
"Deposit must be positive."
);
}
balance += amount;
}
void displayDetails() {
System.out.println("Account Holder: " + accountHolder);
System.out.println("Account Number: " + accountNumber);
System.out.println("Balance: " + balance);
System.out.println("--------------------");
}
}
public class BankAccountApplication {
public static void main(String[] args) {
BankAccount account1 =
new BankAccount("Asha", "AC101", 5000);
BankAccount account2 =
new BankAccount("Rahul", "AC102", 8000);
account1.deposit(1500);
account1.displayDetails();
account2.displayDetails();
}
}
Sample Output
Account Holder: Asha
Account Number: AC101
Balance: 6500.0
--------------------
Account Holder: Rahul
Account Number: AC102
Balance: 8000.0
--------------------
The parameterized constructor initializes each account with the required information. The validation checks reject invalid initial values, while the deposit method validates transactions before updating the balance.
18. Additional Practice Exercises
- Student Constructor: Create a
Student class with name, roll number, and marks. Initialize all fields through a constructor.
- Book Constructor Overloading: Create a
Book class with constructors that accept a title, a title and author, or a title, author, and price.
- Employee Initialization: Create an
Employee class with name, department, and salary. Validate that salary is not negative.
- Rectangle Constructors: Create constructors for a square and a rectangle, then calculate area using a method.
- Constructor Chaining: Create a class with three overloaded constructors and use
this() to delegate to one main constructor.
- Inheritance: Create a
Person superclass and a Student subclass. Use super() to initialize inherited data.
- Private Constructor: Create a utility class whose constructor is private and whose methods are static.
- Validation: Create a
Product class that rejects blank names and negative prices.
19. Interview Questions and Answers
Q1. What is a constructor in Java?
Answer: A constructor is a class member used to initialize a newly created object. It has the same name as its class and does not declare a return type.
Q2. What is the main purpose of a constructor?
Answer: Its main purpose is to initialize an object's fields and establish a valid initial state.
Q3. What is a default constructor?
Answer: It is the no-argument constructor supplied by the compiler when a class declares no constructor.
Q4. What is a no-argument constructor?
Answer: A no-argument constructor accepts no parameters. It can be declared by the programmer or supplied by the compiler as a default constructor when no constructor is declared.
Q5. What is a parameterized constructor?
Answer: It is a constructor that accepts parameters to initialize an object with values provided during creation.
Q6. Can constructors be overloaded?
Answer: Yes. A class can have multiple constructors with different parameter lists.
Q7. Can a constructor have a return type?
Answer: No. A constructor does not declare a return type. If void is written before a class-named declaration, it is a method rather than a constructor.
Q8. Can constructors be inherited?
Answer: No. Constructors are not inherited. A subclass can call a superclass constructor using super().
Q9. Can constructors be overridden?
Answer: No. Constructor overriding is not supported because constructors are not inherited.
Q10. What is constructor chaining?
Answer: Constructor chaining is the process of invoking one constructor from another. The this() expression invokes a constructor in the same class, while super() invokes a superclass constructor.
Q11. What is the difference between this() and super()?
Answer: this() delegates to another constructor in the same class, whereas super() invokes a constructor in the direct superclass.
Q12. What happens if no constructor is declared?
Answer: The compiler provides a default no-argument constructor, subject to the class's superclass constructor requirements.
Q13. What happens if a parameterized constructor is declared but no no-argument constructor exists?
Answer: Java does not automatically add a no-argument constructor. A call such as new Student() will fail to compile unless an accessible no-argument constructor is declared or otherwise available through the relevant type declaration.
Q14. Why use a private constructor?
Answer: A private constructor restricts direct object creation from outside the declaring class. It can be used for utility classes, factory-controlled creation, and some singleton designs.
Q15. Can a constructor be static?
Answer: No. Constructors cannot be declared static because they initialize instances rather than operating as class-level methods.
Q16. Can a constructor throw an exception?
Answer: Yes. A constructor can throw checked or unchecked exceptions, subject to Java's exception rules. This can be useful when initialization fails or supplied values are invalid.
Q17. When is a constructor executed?
Answer: It is executed as part of object creation after the required initialization steps and constructor invocation rules are followed.
Q18. What is the difference between field initialization and constructor initialization?
Answer: Field initializers provide values directly in the class declaration. Constructor initialization uses constructor logic and parameters to set up an object, and both can work together.
Q19. Can a constructor call another method?
Answer: Yes, a constructor can call methods, but it is important to avoid exposing a partially initialized object or invoking overridable methods before subclass initialization is complete.
Q20. Why is constructor validation useful?
Answer: It helps ensure that objects begin in valid states and prevents invalid data from being stored at construction time.
20. Quick Revision Notes
- A constructor initializes a newly created object.
- The constructor name matches the class name.
- A constructor does not declare a return type.
- A default constructor is supplied by the compiler only when no constructor is declared.
- An explicitly declared no-argument constructor can set custom initial values.
- A parameterized constructor accepts input values during object creation.
- Constructor overloading provides multiple initialization options.
this refers to the current object in an instance context.
this() invokes another constructor in the same class.
super() invokes a superclass constructor.
- Constructors are not inherited or overridden.
- Private constructors restrict direct construction from outside the declaring class.
- Constructors can validate inputs and throw exceptions.
- Constructor chaining reduces repeated initialization code.
- Good constructors help establish valid, consistent object states.
21. Conclusion
Constructors are a fundamental part of Core Java and object-oriented programming. They initialize new objects, assign required field values, validate input, and support different ways of creating instances. Understanding default constructors, no-argument constructors, parameterized constructors, and constructor overloading helps you design classes that are easier to use and maintain.
Practicing this(), super(), constructor validation, and access control will strengthen your understanding of object initialization and inheritance. Use the examples and exercises in these notes to build small Java applications before moving on to advanced object-oriented concepts.
For more learning resources, explore the Core Java Training Course, register through the course demo registration page, or visit the JustAcademy website.