What’s New ?

The Top 10 favtutor Features You Might Have Overlooked

Read More

Constructors in Java (with examples)

  • Nov 03, 2023
  • 15 Minutes Read
  • Why Trust Us
    We uphold a strict editorial policy that emphasizes factual accuracy, relevance, and impartiality. Our content is crafted by top technical writers with deep knowledge in the fields of computer science and data science, ensuring each piece is meticulously reviewed by a team of seasoned editors to guarantee compliance with the highest standards in educational content creation and publishing.
  • By Nihal Mahansaria
Constructors in Java (with examples)

Java constructors play a crucial role in object-oriented programming by initializing objects and setting their initial values. These are special methods that are automatically invoked when an object of a class is created. In this guide, we will explore the purpose, types, and usage of constructors in Java, along with practical examples and explanations. 

What are Constructors?

In Java, constructors are a fundamental part of object-oriented programming. They are special methods that initialize objects when they are created. Constructors have the same name as the class and art used to set up the initial state of objects.

Constructor Example

Here's a basic example of a constructor:

public class MyClass {
    private int value;

    // Constructor
    public MyClass() {
        value = 42; // Initialize the 'value' field to 42
    }

    public int getValue() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        MyClass obj = new MyClass(); // Creating an object
        int result = obj.getValue(); // Accessing the initialized value
        System.out.println("Value: " + result);
    }
}

 

Output:

Value: 42

 

In this example, we've defined a constructor for the MyClass class, which initializes the value field to 42 when an object is created. When we create an object and access its value, we get the expected output of 42.

Types of Constructors

Let’s look into the different types of constructors and their examples.

1. Default Constructor

A default constructor is automatically created by the compiler if no constructor is defined in the class. It initializes the object with default values, typically zero for numeric types or null for reference types. Let’s see an example of the same.

Code:

public class DefaultConstructorExample {
    private int value;

    // Default Constructor (automatically created)
    public DefaultConstructorExample() {
        // No need to define this constructor, it's created by the compiler
    }

    public int getValue() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        DefaultConstructorExample obj = new DefaultConstructorExample(); // Creating an object
        int result = obj.getValue(); // Accessing the default value (0 in this case)
        System.out.println("Value: " + result);
    }
}

 

Output:

Value: 0

 

Explanation:

In the above example, the DefaultConstructorExample class has a default constructor that initializes the value field to 0.

2. Parameterized Constructor

Parameterized constructors accept arguments to initialize an object's state. They allow for customization during object creation. Let’s see an example of the same:

Code:

public class ParameterizedConstructorExample {
    private int value;

    // Parameterized Constructor
    public ParameterizedConstructorExample(int initialValue) {
        value = initialValue; // Initialize the 'value' field with the provided value
    }

    public int getValue() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        ParameterizedConstructorExample obj = new ParameterizedConstructorExample(10); // Creating an object with an initial value of 10
        int result = obj.getValue(); // Accessing the initialized value
        System.out.println("Value: " + result);
    }
}

 

Output:

Value: 10

 

Explanation:

In this example, the ParameterizedConstructorExample class has a parameterized constructor that accepts an initial value as an argument, allowing you to customize the object's state during creation.

3. Copy Constructor

A copy constructor is used to create a new object by copying the values of an existing object. It's particularly useful when you want to create a deep copy of an object. Let’s see an example of the same:

Code:

public class CopyConstructorExample {
    private int value;

    // Copy Constructor
    public CopyConstructorExample(CopyConstructorExample other) {
        this.value = other.value; // Copy the value from 'other' object
    }

    public int getValue() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        CopyConstructorExample original = new CopyConstructorExample();
        original.value = 20; // Set an initial value for the original object

        CopyConstructorExample copy = new CopyConstructorExample(original); // Creating a copy
        int result = copy.getValue(); // Accessing the copied value
        System.out.println("Copied Value: " + result);
    }
}

 

Output:

Copied Value: 20

 

Explanation:

In this example, the CopyConstructorExample class has a copy constructor that takes an instance of the same class as its parameter. It copies the value from the original object to create a new object.

What is Constructor Overloading?

Constructor overloading allows a class to have multiple constructors with different parameter lists. This provides flexibility when creating objects.

Let’s understand it better with an example.

Code:

public class ConstructorOverloadingExample {
    private int value;

    // Constructor with no parameters
    public ConstructorOverloadingExample() {
        value = 0; // Default initialization
    }

    // Constructor with a single parameter
    public ConstructorOverloadingExample(int initialValue) {
        value = initialValue; // Initialize with the provided value
    }

    public int getValue() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        ConstructorOverloadingExample obj1 = new ConstructorOverloadingExample(); // Using the default constructor
        ConstructorOverloadingExample obj2 = new ConstructorOverloadingExample(5); // Using the parameterized constructor

        int result1 = obj1.getValue();
        int result2 = obj2.getValue();

        System.out.println("Value 1: " + result1);
        System.out.println("Value 2: " + result2);
    }
}

 

Output:

Value 1: 0
Value 2: 5

 

In the ConstructorOverloadingExample class, we've overloaded the constructor by providing two different constructors - one without any parameters and one with a single parameter. This allows you to create objects in multiple ways, depending on your requirements.

Syntax and Usage of Constructors

Let's dive deeper into the initialization and use cases of constructors.

1. Creating a Constructor

To create a constructor in Java, you need to follow these rules:

  • The constructor name must match the class name.
  • Constructors don't have a return type, not void.
  • You can have multiple constructors in a class, as long as they have different parameter lists.

Here's an example of creating a constructor:

public class ConstructorSyntaxExample {
    private int value;

    // Constructor
    public ConstructorSyntaxExample(int initialValue) {
        value = initialValue; // Initialize the 'value' field with the provided value
    }

    public int getValue() {
        return value;
    }
}

 

In this example, the ConstructorSyntaxExample class has a constructor that initializes the value field with the provided initial value.

2. Constructor Name and Class Name

The name of a constructor must match the class name. This is how Java knows which constructor to call when creating an object.

Let’s understand the naming convention better with an example:

public class ConstructorNameExample {
    private int value;

    // Constructor (with the same name as the class)
    public ConstructorNameExample(int initialValue) {
        value = initialValue;
    }

    public int getValue() {
        return value;
    }
}

 

3. Initializing Object State

One of the primary purposes of a constructor is to initialize the state of an object. You can set the initial values for the object's fields within the constructor.

Let’s dive into it’s implementation:

public class InitializeStateExample {
    private int value;

    // Constructor
    public InitializeStateExample(int initialValue) {
        value = initialValue; // Initialize the 'value' field with the provided value
    }

    public int getValue() {
        return value;
    }
}

 

4. Calling Constructors

Constructors are called when you create an object using the new keyword. The appropriate constructor is automatically selected based on the arguments you provide.

Let’s understand this with an example:

public class ConstructorCallExample {
    private int value;

    // Constructor
    public ConstructorCallExample(int initialValue) {
        value = initialValue; // Initialize the 'value' field with the provided value
    }

    public int getValue() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        ConstructorCallExample obj = new ConstructorCallExample(15); // Creating an object with an initial value of 15
        int result = obj.getValue(); // Accessing the initialized value
        System.out.println("Value: " + result);
    }
}

 

Output:

Value: 15

 

Explanation:

In the example above, we create an object of the ConstructorCallExample class by calling its constructor with an initial value of 15.

5. Implicit and Explicit Constructor Calls

When you create an object, you can implicitly or explicitly call a constructor. An explicit constructor call involves specifying the constructor you want to use, while an implicit call relies on Java's default behavior.

Here's an example of the same:

public class ConstructorCallsExample {
    private int value;

    // Constructor
    public ConstructorCallsExample(int initialValue) {
        value = initialValue; // Initialize the 'value' field with the provided value
    }

    public int getValue() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        ConstructorCallsExample obj1 = new ConstructorCallsExample(20); // Explicit constructor call
        ConstructorCallsExample obj2 = new ConstructorCallsExample(); // Implicit constructor call

        int result1 = obj1.getValue();
        int result2 = obj2.getValue();

        System.out.println("Value 1: " + result1);
        System.out.println("Value 2: " + result2);
    }
}

 

Output:

Value 1: 20
Value 2: 0

 

Explanation:

In the example above, the first object (obj1) is created with an explicit constructor call that initializes the value field to 20. The second object (obj2) is created implicitly with an implicit constructor call, resulting in the default initialization of 0 for the value field.

When and How Default Constructors are created

Let’s explore more about default constructors and their use cases:

When and How It's Created

A default constructor is automatically created by the Java compiler if no constructor is defined in a class. This happens under the following circumstances:

  • If you don't define any constructors in your class.
  • If you define at least one constructor with arguments and don't explicitly provide a no-argument constructor.

Let's see an example:

public class DefaultConstructorExample {
    private int value;

    // No constructors defined in this class

    public int getValue() {
        return value;
    }
}

 

In this example, we haven't defined any constructors explicitly. As a result, the Java compiler automatically provides a default constructor for the DefaultConstructorExample class.

Default Constructor's Role in Object Initialization

The default constructor plays a crucial role in object initialization when no other constructor is specified. It initializes the object with default values, typically zero for numeric types or null for reference types.

Let’s see an example:

public class DefaultConstructorRoleExample {
    private int value;

    // No constructors defined in this class

    public int getValue() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        DefaultConstructorRoleExample obj = new DefaultConstructorRoleExample(); // Creating an object
        int result = obj.getValue(); // Accessing the default value (0 in this case)
        System.out.println("Value: " + result);
    }
}

 

Output:

Value: 0

 

Explanation:

In this example, the DefaultConstructorRoleExample class doesn't define any constructors explicitly. As a result, a default constructor is created by the compiler, and when we create an object, it initializes the value field with the default value of 0.

The default constructor is especially important when you want to create objects without passing any arguments or providing custom initialization logic.

When and How Parameterized Constructors are created

Let’s explore more about parameterized constructors and their use cases:

Defining and Using Parameters

Parameterized constructors allow you to initialize an object's state by providing one or more parameters when creating an object. This is particularly useful when you need to customize the object's state during construction.

Let’s understand this better with an example:

public class ParameterizedConstructorExample {
    private int value;

    // Parameterized Constructor
    public ParameterizedConstructorExample(int initialValue) {
        value = initialValue; // Initialize the 'value' field with the provided value
    }

    public int getValue() {
        return value;
    }
}

 

Explanation:

In this example, the ParameterizedConstructorExample class has a parameterized constructor that accepts an initial value as a parameter. This allows you to set the object's state during object creation.

Initializing Object State with Parameters

When you create an object using a parameterized constructor, you can pass values that are used to initialize the object fields.

Let’s understand this better with an example:

public class ParameterizedConstructorUsageExample {
    private int value;

    // Parameterized Constructor
    public ParameterizedConstructorUsageExample(int initialValue) {
        value = initialValue; // Initialize the 'value' field with the provided value
    }

    public int getValue() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        ParameterizedConstructorUsageExample obj = new ParameterizedConstructorUsageExample(30); // Creating an object with an initial value of 30
        int result = obj.getValue(); // Accessing the initialized value
        System.out.println("Value: " + result);
    }
}

 

Output:

Value: 30

 

Explanation:

In the example above, the ParameterizedConstructorUsageExample class defines a parameterized constructor that accepts an initial value. When we create an object and pass 30 as the parameter, the value field is initialized with the provided value.

Constructor Chaining

Constructor chaining is a technique of constructor called another constructor within the class. This can be useful to avoid duplicating initialization logic.

Let’s understand this better with an example:

public class ConstructorChainingExample {
    private int value;

    // Constructor with no arguments
    public ConstructorChainingExample() {
        // Call the parameterized constructor with a default value of 0
        this(0);
    }

    // Parameterized Constructor
    public ConstructorChainingExample(int initialValue) {
        value = initialValue; // Initialize the 'value' field with the provided value
    }

    public int getValue() {
        return value;
    }
}

 

Explanation:

In this example, the ConstructorChainingExample class has two constructors. The default constructor calls the parameterized constructor with a default value of 0 using this(0).

public class Main {
    public static void main(String[] args) {
        ConstructorChainingExample obj = new ConstructorChainingExample(); // Creating an object using the default constructor
        int result = obj.getValue(); // Accessing the initialized value
        System.out.println("Value: " + result);
    }
}

 

Output:

Value: 0

 

Explanation:

When we create an object using the default constructor, it calls the parameterized constructor with an initial value of 0, resulting in an object with a value of 0.

When and How Copy Constructors are created

Let’s explore more about copy constructors and their use cases:

Creating a Copy Constructor

A copy constructor is a special type of constructor used to create a new object by copying the values from an existing object. It's particularly useful when you want to duplicate the state of an object.

Here’s an example:

public class CopyConstructorExample {
    private int value;

    // Copy Constructor
    public CopyConstructorExample(CopyConstructorExample other) {
        this.value = other.value; // Copy the value from the 'other' object
    }

    public int getValue() {
        return value;
    }
}

 

In this example, the CopyConstructorExample class has a copy constructor that takes an instance of the same class as its parameter and copies the value field from the other object.

Purpose and Use of Copy Constructors

The purpose of a copy constructor is to create a deep copy of an object, ensuring that the new object is independent of the original. It's commonly used in scenarios where you need to duplicate the stete of an object without sharing references to the same data.

Let’s see an example:

public class CopyConstructorUsageExample {
    private int value;

    // Copy Constructor
    public CopyConstructorUsageExample(CopyConstructorUsageExample other) {
        this.value = other.value; // Copy the value from the 'other' object
    }

    public int getValue() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        CopyConstructorUsageExample original = new CopyConstructorUsageExample();
        original.value = 25; // Set an initial value for the original object

        CopyConstructorUsageExample copy = new CopyConstructorUsageExample(original); // Creating a copy
        int result = copy.getValue(); // Accessing the copied value
        System.out.println("Copied Value: " + result);
    }
}

 

Output:

Value: 25

 

Explanation:

In this example, we have an original object, and we create a copy of it using the copy constructor. The copy constructor ensures that the new copy object has its independent copy of the value, and changes to one object don't affect the other.

Copy constructors are valuable when working with complex data structures and want to ensure data integrity by duplicating objects instead of sharing references.

More About Constructor Overloading

Let’s explore various scenarios in constructor overloading:

1. Multiple Constructors in a Class

In Java, you can have multiple constructors within a single class. This concept is known as constructor overloading. Each constructor must have a unique parameter list, allowing you to create objects with different initialization options.

Let’s see an example:

public class ConstructorOverloadingExample {
    private int value;

    // Constructor with no parameters
    public ConstructorOverloadingExample() {
        value = 0; // Default initialization
    }

    // Constructor with a single parameter
    public ConstructorOverloadingExample(int initialValue) {
        value = initialValue; // Initialize with the provided value
    }

    public int getValue() {
        return value;
    }
}

 

Explanation:

In this example, the ConstructorOverloadingExample class demonstrates constructor overloading with two constructors—one with no parameters and another with a single int parameter.

2. Overloading Rules and Method Signature

When overloading constructors (or methods), the key is to have a different method signature for each constructor. The method signature includes the method's neme end the types and order of its parameters.

Here’s an example:

public class ConstructorOverloadingRulesExample {
    private int value;

    // Constructor with an int parameter
    public ConstructorOverloadingRulesExample(int initialValue) {
        value = initialValue; // Initialize with the provided value
    }

    // Overloaded constructor with a String parameter
    public ConstructorOverloadingRulesExample(String initialValue) {
        value = Integer.parseInt(initialValue); // Initialize with the converted value from the String
    }

    public int getValue() {
        return value;
    }
}

 

In this example, the ConstructorOverloadingRulesExample class demonstrates constructor overloading with two constructors—one accepting an int and another accepting a String.

3. Selecting the Appropriate Constructor

When you create an object, Java automatically selects the most appropriate constructor based on the arguments you provide. If you provide an int argument, the constructor that accepts an int will be called. If you provide a String argument, the constructor that accepts a String will be called.

public class ConstructorSelectionExample {
    private int value;

    // Constructor with an int parameter
    public ConstructorSelectionExample(int initialValue) {
        value = initialValue; // Initialize with the provided int value
    }

    // Overloaded constructor with a String parameter
    public ConstructorSelectionExample(String initialValue) {
        value = Integer.parseInt(initialValue); // Initialize with the converted value from the String
    }

    public int getValue() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        ConstructorSelectionExample obj1 = new ConstructorSelectionExample(42); // Calling the int parameter constructor
        ConstructorSelectionExample obj2 = new ConstructorSelectionExample("37"); // Calling the String parameter constructor

        int result1 = obj1.getValue();
        int result2 = obj2.getValue();

        System.out.println("Value 1: " + result1);
        System.out.println("Value 2: " + result2);
    }
}

 

Output:

Value 1: 42
Value 2: 37

 

Explanation:

In this example,  we create two objects, obj1 and obj2, with different types of arguments. Java selects the appropriate constructor based on the argument type, allowing you to create objects with different initializations.

Constructor Best Practices

Following a certain set of practices could make the usage of constructors much more easier and efficient. Some of them are:

A. Encapsulation and Constructor Access Modifiers

Encapsulation is a fundamental concept in object-oriented programming. Constructors can be used to ensure that objects are created in a valid and consistent state. By controlling the access to object fields through constructors, you can enforce encapsulation.

Here's an example:

public class EncapsulationExample {
    private int value;

    // Private constructor to enforce encapsulation
    private EncapsulationExample(int initialValue) {
        value = initialValue; // Initialize with the provided value
    }

    // Public factory method for object creation
    public static EncapsulationExample create(int initialValue) {
        if (initialValue >= 0) {
            return new EncapsulationExample(initialValue);
        } else {
            throw new IllegalArgumentException("Initial value must be non-negative.");
        }
    }

    public int getValue() {
        return value;
    }
}

 

In this example, we use a private constructor to enforce encapsulation and a public factory method, create, for creating objects. The factory method ensures that the initial value is non-negative.

B. Constructor vs. Static Factory Methods

In addition to constructors, Java allows the use of static factory methods for object creation. Static factory methods offer more flexibility and descriptive names, making them a valuable alternative to constructors.

Let's see the implementation:

public class StaticFactoryExample {
    private int value;

    // Private constructor
    private StaticFactoryExample(int initialValue) {
        value = initialValue;
    }

    // Static factory method
    public static StaticFactoryExample createWithInitialValue(int initialValue) {
        return new StaticFactoryExample(initialValue);
    }

    public int getValue() {
        return value;
    }
}

 

In this example, we use a static factory method, createWithInitialValue, to create objects. This approach provides a clear and descriptive way to initialize objects.

C. Using Constructors for Dependency Injection

Constructors are commonly used for dependency injection, a design pattern that promotes loosely coupled classes. By injecting dependencies through constructors, you can make your code more testable and maintainable.

public class DependencyInjectionExample {
    private final Logger logger;

    // Constructor with a Logger dependency
    public DependencyInjectionExample(Logger logger) {
        this.logger = logger;
    }

    public void logMessage(String message) {
        logger.log(message);
    }
}

 

In this example, the DependencyInjectionExample class receives a Logger dependency through its constructor, enabling the injection of different logging implementations.

Common Pitfalls while using Constructors

While using constructors, one might come accross some common erros and pitfalls. Some of them are:

A. Constructor Ambiguity

Constructor ambiguity occurs when multiple constructors in a class have similar parameter lists, making it unclear which constructor should be called. This can lead to compilation errors.

public class ConstructorAmbiguityExample {
    private int value;

    // Constructor with an int parameter
    public ConstructorAmbiguityExample(int initialValue) {
        value = initialValue; // Initialize with the provided value
    }

    // Another constructor with an int parameter
    public ConstructorAmbiguityExample(int anotherValue) {
        value = anotherValue; // Initialize with the provided value
    }

    public int getValue() {
        return value;
    }
}

 

In this example, both constructors have the same parameter type (int), which can lead to ambiguity issues when creating objects with an int argument.

B. Initializing Order Issues

In some cases, initialization order can be a pitfall. If you have multiple constructors or complex initialization logic, it's essential to ensure that objects are initialized correctly and consistently.

Let's see an example:

public class InitializationOrderExample {
    private int value;

    // Constructor with an int parameter
    public InitializationOrderExample(int initialValue) {
        value = initialValue; // Initialize with the provided value
    }

    // Another constructor with no parameters
    public InitializationOrderExample() {
        value = 10; // Initialize with a default value
    }

    public int getValue() {
        return value;
    }
}

 

In this example, there are two constructors with different initialization logic. Depending on the constructor used, the order of initialization can differ, leading to unexpected behavior.

C. Constructor Exception Handling

Constructors can throw exceptions during object creation. It's crucial to handle exceptions appropriately to ensure that objects are constructed safely.

public class ConstructorExceptionHandlingExample {
    private int value;

    // Constructor that can throw an exception
    public ConstructorExceptionHandlingExample(int initialValue) {
        if (initialValue < 0) {
            throw new IllegalArgumentException("Initial value must be non-negative.");
        }
        value = initialValue; // Initialize with the provided value
    }

    public int getValue() {
        return value;
    }
}

 

In this example, the constructor throws an IllegalArgumentException if the initial value is negative. Failing to handle such exceptions can lead to runtime errors. 

Conclusion

In this article, we have explored the purpose, types, and usage of constructors in Java. Constructors play a vital role in object initialization and allow for flexible and customizable object creation. By using constructors effectively, you can ensure that objects are created in a valid and consistent state, with their attributes properly initialized.

FavTutor - 24x7 Live Coding Help from Expert Tutors!

About The Author
Nihal Mahansaria
As a computer science student with a passion for technology and a drive to learn, I have developed a diverse set of skills in web development, machine learning, and technical content writing. With experience in multiple front-end and back-end frameworks, including Flask and Python, I am able to create scalable and efficient web applications.