How can you restrict object creation of a class in Java?

There are several ways to restrict object creation of a class in Java, depending on the level of restriction you want to enforce. Here are the most common techniques:

1. Private Constructor:

This is the most common and effective way to prevent direct instantiation of a class. By making the constructor private, you prevent any class outside of the class itself from creating instances.

public class MyRestrictedClass {

    private MyRestrictedClass() {
        // Private constructor - no one outside this class can create an instance
    }

    public static MyRestrictedClass getInstance() {
        return new MyRestrictedClass(); // Only the class itself can create an instance
    }

    // Other methods...
}

public class Main {
    public static void main(String[] args) {
        // MyRestrictedClass obj = new MyRestrictedClass(); // Compile-time error!
        MyRestrictedClass obj = MyRestrictedClass.getInstance(); // Correct way to get an instance
    }
}

This pattern is often used for singleton classes (where you only want one instance of the class) or utility classes (classes with static methods and no instance variables). The getInstance() method acts as a factory, controlling how and when instances are created (or if they are created at all).


2. Factory Class :

You can create a separate factory class whose sole purpose is to create instances of the restricted class. The restricted class can have a protected or default constructor, allowing the factory class (which is likely in the same package) to create instances, but preventing other classes from doing so.

// Restricted class (in package 'mypackage')
class MyRestrictedClass {
    MyRestrictedClass() { } // Default constructor (accessible within the package)
}

// Factory class (in package 'mypackage')
class MyRestrictedClassFactory {
    public static MyRestrictedClass createInstance() {
        return new MyRestrictedClass();
    }
}

// Main class (in a different package, or even the same)
public class Main {
    public static void main(String[] args) {
        // MyRestrictedClass obj = new MyRestrictedClass(); // Compile-time error (if in a different package)
        MyRestrictedClass obj = MyRestrictedClassFactory.createInstance(); // OK
    }
}




3. Abstract Class:

If you declare a class as abstract, you cannot create instances of it directly. You can only create instances of its concrete subclasses. This is useful when you want to define a common interface or behavior but don't want to allow direct instantiation of the base class.

abstract class MyAbstractClass {
    // ... abstract methods ...
}

class MyConcreteClass extends MyAbstractClass {
    // ... implementation of abstract methods ...
}

public class Main {
    public static void main(String[] args) {
        // MyAbstractClass obj = new MyAbstractClass(); // Compile-time error!
        MyConcreteClass obj = new MyConcreteClass(); // OK
    }
}

 

4. Using an Interface (with a Factory):

You can combine an interface with a factory class. The interface defines the contract, and the factory class creates instances of a class that implements the interface. This provides flexibility and hides the concrete implementation.

interface MyInterface {
    // ... interface methods ...
}

class MyClass implements MyInterface {
    private MyClass() {} // Private constructor
    // ... implementation ...
}

class MyFactory {
    public static MyInterface create() {
        return new MyClass();
    }
}

 

Choosing the Right Approach :

  • Singleton/Utility Classes: Private constructor.
  • Controlled Instantiation within a Package: Factory class with default or protected constructor.
  • Defining a Blueprint, Preventing Direct Instantiation: Abstract class.
  • Flexibility and Hiding Implementation: Interface with a factory.

The private constructor approach is generally the most straightforward and commonly used when you want to completely prevent direct instantiation of a class. The other methods offer varying degrees of control and flexibility depending on your specific design requirements.