Constructors

About

A constructor in Java is a special method used to initialize objects. It is automatically called when an object is created. The main purpose of a constructor is to assign initial values to the object's fields.

Characteristics of a Constructor

Same Name as Class

A constructor must have the same name as the class.

class Person {
    Person() {  // Constructor name = Class name
        System.out.println("Person object created!");
    }
}

No Return Type

Unlike methods, constructors do not have a return type (not even void).

class Example {
    Example() {  // Constructor
        System.out.println("Object initialized!");
    }
}

Automatically Called

It executes when an object is created using new.

Example obj = new Example();  // Constructor runs automatically

Can Have Parameters

Just like methods, constructors can accept parameters to initialize object values.

class Car {
    String brand;
    
    Car(String brand) {  // Parameterized constructor
        this.brand = brand;
    }
}

Can Have Multiple Constructors (Constructor Overloading)

Java allows multiple constructors with different parameter lists (overloading).

class Person {
    Person() { System.out.println("Default Constructor!"); }
    Person(String name) { System.out.println("Hello, " + name); }
}

Can have access modifiers

Constructors in Java can have access modifiers just like methods and fields. The access modifier of a constructor determines where it can be accessed.

Access Modifiers for Constructors

Access Modifier
Description

public

The constructor is accessible from anywhere in the project.

private

The constructor is accessible only within the same class (used in Singleton pattern).

  • Prevents direct object creation from outside the class.

  • Used in Singleton Pattern to ensure only one instance exists.

protected

The constructor is accessible within the same package and in subclasses.

  • Allows access within the same package and in subclasses.

  • Used when creating an abstract class with a protected constructor.

default (no modifier)

The constructor is accessible only within the same package.

// Public Constructor
// ---------------------------------------
class Person {
    public Person() {  // Public Constructor
        System.out.println("Person object created!");
    }
}

public class Main {
    public static void main(String[] args) {
        Person p = new Person();  // Allowed
    }
}
// ---------------------------------------

// Private Constructor (Singleton Pattern)
// ---------------------------------------
class Singleton {
    private static Singleton instance;

    private Singleton() {  // Private Constructor
        // The message appears only once, proving that only one instance is created.
        System.out.println("Singleton Instance Created!");
    }

    public static Singleton getInstance() {
        if (instance == null)
            instance = new Singleton();
        return instance;
    }
}

public class Main {
    public static void main(String[] args) {
        // Singleton s = new Singleton(); // Not Allowed (Compilation Error)
        Singleton s1 = Singleton.getInstance();  // Allowed
        Singleton s2 = Singleton.getInstance();  // Same instance returned
    }
}
// ---------------------------------------

// Protected Constructor (Inheritance)
// ---------------------------------------
class Animal {
    protected Animal() {  // Protected Constructor
        System.out.println("Animal object created!");
    }
}

class Dog extends Animal {
    Dog() {
        super();  // Allowed in subclass
        System.out.println("Dog object created!");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog d = new Dog();  // Allowed
    }
}
// ---------------------------------------

// Default (Package-Private) Constructor
// ---------------------------------------
class Car {
    Car() {  // Default Constructor (No Modifier)
        System.out.println("Car object created!");
    }
}

public class Main {
    public static void main(String[] args) {
        Car c = new Car();  // Allowed (same package)
    }
}

package anotherPackage;
import myPackage.Car;

public class Test {
    public static void main(String[] args) {
        Car c = new Car();  // Not Allowed (Compilation Error)
    }
}
// ---------------------------------------

Example

class Car {
    String brand;
    int speed;

    // Constructor
    Car(String brand, int speed) {
        this.brand = brand;
        this.speed = speed;
        System.out.println(brand + " car created with speed " + speed + " km/h.");
    }
}

public class Main {
    public static void main(String[] args) {
        Car car1 = new Car("Toyota", 120);
        Car car2 = new Car("Honda", 100);
        /* Output:
            Toyota car created with speed 120 km/h.
            Honda car created with speed 100 km/h.
        */
    }
}

Types of Constructors in Java

1. Default Constructor (No-Argument Constructor)

A constructor without parameters that initializes default values.

class Dog {
    String breed;
    
    Dog() {  // Default constructor
        breed = "Unknown";
        System.out.println("A dog is created!");
    }
}
Dog d = new Dog();  // Output: A dog is created!

2. Parameterized Constructor

A constructor that accepts arguments to initialize object fields.

class Laptop {
    String brand;
    
    Laptop(String brand) {  // Parameterized constructor
        this.brand = brand;
    }
}

Usage:

Laptop l = new Laptop("Dell");
System.out.println(l.brand);  // Output: Dell

3. Copy Constructor

A constructor that copies values from another object.

class Book {
    String title;

    // Parameterized Constructor
    Book(String title) {
        this.title = title;
    }

    // Copy Constructor
    Book(Book b) {
        this.title = b.title;
    }
}

Usage:

Book b1 = new Book("Java Programming");
Book b2 = new Book(b1);
System.out.println(b2.title);  // Output: Java Programming

4. Private Constructor

A constructor that is private to prevent object creation. Used in Singleton Design Pattern.

class Singleton {
    private static Singleton instance;
    
    private Singleton() { }  // Private Constructor
    
    public static Singleton getInstance() {
        if (instance == null)
            instance = new Singleton();
        return instance;
    }
}

Usage:

Singleton obj = Singleton.getInstance();  // Only one instance allowed

5. Constructor Overloading

A class can have multiple constructors with different parameters.

class Student {
    String name;
    int age;

    // Constructor Overloading
    Student() { name = "Unknown"; age = 0; }
    Student(String name) { this.name = name; }
    Student(String name, int age) { this.name = name; this.age = age; }
}

Usage:

Student s1 = new Student();  
Student s2 = new Student("Alice");  
Student s3 = new Student("Bob", 20);  

Can we have Destructors in Java?

Java does not have destructors like C++, but it provides finalization mechanisms for resource cleanup.

Why No Destructors in Java?

  1. Garbage Collection Handles Memory Cleanup:

    • In Java, objects are automatically garbage collected when they are no longer referenced.

    • Unlike C++, where destructors explicitly free memory, Java depends on the JVM's garbage collector.

  2. No Explicit Object Destruction:

    • In C++, destructors (~ClassName()) are used for manual cleanup of allocated memory and resources.

    • In Java, there is no direct equivalent because objects are deallocated by the JVM's garbage collector, making explicit destruction unnecessary.

Alternatives to Destructors in Java

1. finalize() (Deprecated)

  • Java provided a finalize() method in Object class as a cleanup mechanism, but it was unreliable and has been deprecated in Java 9.

  • Called before garbage collection, but not guaranteed to execute immediately or at all.

class Example {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("Finalize method called");
    }
}

Why Avoid finalize()?

  • Unpredictable execution (depends on garbage collection timing).

  • Causes performance overhead.

  • Might not run before program exit.

2. try-with-resources (Preferred Approach)

For managing resources like files, database connections, sockets, etc., Java provides the try-with-resources mechanism. Classes that implement AutoCloseable or Closeable can be automatically closed when the block exits.

try (FileReader reader = new FileReader("file.txt")) {
    // Read file
} catch (IOException e) {
    e.printStackTrace();
} 
// FileReader automatically closed here

3. Explicit close() Method

For manual cleanup, define a close() method and call it explicitly.

class Resource implements AutoCloseable {
    void useResource() {
        System.out.println("Using resource...");
    }

    @Override
    public void close() {
        System.out.println("Resource closed.");
    }
}

public class Main {
    public static void main(String[] args) {
        try (Resource res = new Resource()) {
            res.useResource();
        } 
        // Resource gets closed automatically here
    }
}

Recommended for managing non-memory resources like files, sockets, database connections.

Last updated

Was this helpful?