Skip to main content

How to Break Singleton Design Pattern in Java

A Singleton design pattern is used to ensure a class has only one instance and provides a global point of access to it. However, this pattern can be broken using several advanced Java features.

1. Standard Singleton Implementation

To create a robust singleton class, you need:

  • A private static instance of the class.
  • A private constructor to prevent external instantiation.
  • A public static method (e.g., getInstance()) that returns the instance.
public class Singleton implements Serializable, Cloneable {
private static Singleton instance;

private Singleton() {
// Private constructor
}

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

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

2. Breaking using Reflection

Reflection can be used to change the visibility of the private constructor at runtime, allowing you to create multiple instances.

  • Method: Use setAccessible(true) on the constructor.
  • Result: The new instance will have a different hashcode than the original.
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton brokenInstance = constructor.newInstance();

3. Breaking using Serialization

When an object is serialized and then deserialized, Java creates a new instance of the class by default.

  • Pre-requisite: The class must implement Serializable.
  • Result: The deserialized object is a new instance with a unique memory address.
// Serialize original instance to a file
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton.ser"));
oos.writeObject(originalInstance);

// Deserialize to create a new instance
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("singleton.ser"));
Singleton brokenInstance = (Singleton) ois.readObject();

4. Breaking using Cloning

If a Singleton class implements the Cloneable interface, the clone() method can be used to bypass the singleton property.

  • Method: Call the clone() method on the existing instance.
  • Result: A new instance is created with the same field values but a different hashcode.
Singleton brokenInstance = (Singleton) originalInstance.clone();

Summary of Hashcodes

In a properly functioning Singleton, the hashcode for any requested instance should be identical. When broken via the methods above, you will observe:

  • Original Instance Hashcode: 1234567
  • Broken Instance Hashcode: 9876543