In Sharing Learning from Excellent Lessons, we explored three main ways to destroy the properties of a single case and how to prevent it.Share it for your reference.
We are accustomed to using the singleton design pattern in our applications when needed.It is well known that in a single design pattern, we can only create one instance and access it throughout the application.In some cases, however, it will break the singleton behavior.
In three main concepts, we can break the singleton property of the Singleton class in Java.In this article, we will discuss how to destroy it and how to prevent it.
These are the sample Singleton and SingletonTest classes.
Singleton.
Singleton.Java
package demo1; public final class Singleton { private static volatile Singleton instance = null; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
SingletonTest.java
package demo1; public class SingletonTest { public static void main(String[] args) { Singleton object1 = Singleton.getInstance(); Singleton object2 = Singleton.getInstance(); System.out.println("Hashcode of Object 1 - " + object1.hashCode()); System.out.println("Hashcode of Object 2 - " + object2.hashCode()); } }
This is the output; you can see that it has the same hashcode as objectOne and objectTwo:
Hashcode of Object 1 - 1836019240 Hashcode of Object 2 - 1836019240
Now, we're going to break that pattern.First, we'll use Java reflection.
reflex
Java Reflection is an API for checking or modifying the behavior of methods, classes, and interfaces at run time.Using the Reflection API, we can create multiple objects in the Singleton class.Consider the following example:
ReflectionSingleton.java
package demo1; import java.lang.reflect.Constructor; public class ReflectionSingleton { public static void main(String[] args) { Singleton objOne = Singleton.getInstance(); Singleton objTwo = null; try { Constructor constructor = Singleton.class.getDeclaredConstructor(); constructor.setAccessible(true); objTwo = (Singleton) constructor.newInstance(); } catch (Exception ex) { System.out.println(ex); } System.out.println("Hashcode of Object 1 - "+objOne.hashCode()); System.out.println("Hashcode of Object 2 - "+objTwo.hashCode()); } }
This example shows how reflection breaks the singleton pattern with Java reflection.You will get two hash codes, as shown below.It breaks through the singleton pattern.
Prevent singleton mode reflection
There are many ways to prevent reflecting the Singleton pattern in the API, but one of the best solutions is to raise a runtime exception in the constructor if an instance already exists.In this case, we cannot create a second instance.
Deserialize
In serialization, we can save the object of the byte stream to a file or send it over the network.Assuming you serialize the Singleton class and then deserialize the object again, it will create a new instance, so deserialization will break the Singleton pattern.
The following code illustrates how a single inverse pattern is interrupted by deserialization.
Implement the Serializable interface for the Singleton class.
DeserializationSingleton.Java
package demo1; import java.io.*; public class DeserializationSingleton { public static void main(String[] args) throws Exception { Singleton instanceOne = Singleton.getInstance(); ObjectOutput out = new ObjectOutputStream(new FileOutputStream("file.text")); out.writeObject(instanceOne); out.close(); ObjectInput in = new ObjectInputStream(new FileInputStream("file.text")); Singleton instanceTwo = (Singleton) in.readObject(); in.close(); System.out.println("hashCode of instance 1 is - " + instanceOne.hashCode()); System.out.println("hashCode of instance 2 is - " + instanceTwo.hashCode()); } }
The output is as follows, and you can see two hashcodes.
hashCode of instance 1 is - 2125039532 hashCode of instance 2 is - 381259350
Prevent Singleton Mode Deserialization
To overcome this problem, we need to override the readResolve() method in the Singleton class and return the same Singleton instance.Update Singleton.java using the following methods.
protected Object readResolve() { return instance; }
Now run the DeserializationDemo class above and view the output.
hashCode of instance 1 is - 2125039532 hashCode of instance 2 is - 2125039532
Clone
Using the Clone method, we can create a copy of the original object; this is the same thing if we apply cloning in the singleton mode.It creates two instances: one and the other.In this case, we'll break the Singleton principle, as shown in the code below.
Implement the Clonable interface and override the clone method in the Singleton category above
Singleton.java
@Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
Then, test the clone to break the singleton.
CloningSingleton.java
public class CloningSingleton { public static void main(String[] args) throws CloneNotSupportedException, Exception { Singleton instanceOne = Singleton.getInstance(); Singleton instanceTwo = (Singleton) instanceOne.clone(); System.out.println("hashCode of instance 1 - " + instanceOne.hashCode()); System.out.println("hashCode of instance 2 - " + instanceTwo.hashCode()); } }
This is the output:
hashCode of instance 1 - 1836019240 hashCode of instance 2 - 325040804
If we see the output above, the two instances have different hashcodes.This means that these instances are different.
Prevent single-case pattern cloning
In the code above, it breaks the Singleton principle.e Two instances were created.To overcome these issues, we need to implement/override the clone() method and throw an exception CloneNotSupportedException from the clone method.If someone tries to create a clone object of Singleton, it will throw an exception, as shown in the code below.
@Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); }
Now we can run the loningSingleton class; when creating a cloned object of a single object, it will throw CloneNotSupportedException.
This article is written here. If there are any deficiencies, you are welcome to add comments. I hope this article is useful to you!