Today we will discuss about how to create fully Singleton class in Java. Before jumping to creation of Singleton class, lets list down some of the key features and usage of creating Singleton class in Java.
What is Singleton design pattern class?
In simple words Singleton class is nothing but having a single object or Instance of a class for entire lifetime of the application.
Singleton pattern is a common pattern we use in our day today code and projects in various places like reading a property file values, DB Connections etc., Restricting multiple Object or Instance creation on Class. Main property of singleton class is restricting the class Instance creation from outside Singleton class. This can be achieved by keeping private constructors.
Even by keeping private constructors other programmers can break singleton pattern and they can create instance outside class by other Java features like clone() and serialization. To avoid these loop hols we need to @Override clone() and readResolve() methods in our Singleton class.
We can achieve this in 2 ways like Lazy initialization and Eager initialization in the class. Below are the small example which will explain about the Fully Singleton implementation by using Lazy initialization.
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.Random;
import javax.management.InstanceAlreadyExistsException;
class MySingleton implements Serializable {
private static MySingleton obj = null;
private int val;
private MySingleton() throws InstanceAlreadyExistsException{
if(obj != null){
System.out.println("\nObject already created....");
throw new InstanceAlreadyExistsException();
}
System.out.println("Inside Constructor..");
val = new Random().nextInt();
}
public static MySingleton getInstance() throws InstanceAlreadyExistsException{
if(obj == null){
synchronized (MySingleton.class) {
if(obj == null){
obj = new MySingleton();
}
}
}
return obj;
}
public int getVal(){
return val;
}
public void setVal(int val){
this.val = val;
}
@Override
protected MySingleton clone() throws CloneNotSupportedException {
// If user tries to clone the object then we are sending same class object
try {
return MySingleton.getInstance();
} catch (InstanceAlreadyExistsException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
private Object readResolve() throws ObjectStreamException, InstanceAlreadyExistsException {
// We are blocking deserilizing object and sending same class object
return MySingleton.getInstance();
}
}
Above MySingleton class contains private constructor, getter, setter, @Override clone method, readResolve method and static method to get the class instance. Apart from that we have class member variables like MySingleton (obj) and val. In constructor just we have assigned some random value to val just for identifying multiple instance has created are we are using same instance throughout the application and next we are throwing exception called InstanceAlreadyExistsException if already class instance created. Here we are blocking other user to create instance using java.lang.reflect.Constructor class to satisfy fully singleton pattern.
In static method we are using double to identify class has already initialized or not. If already initialized then method we will return Object (obj) else condition will go inside synchronized block. Here we are using synchronized block to avoid multiple object creation under multi-threading.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
public class SingletonPattern {
public static void main(String[] args) {
try{
MySingleton obj1 = MySingleton.getInstance();
MySingleton obj2 = obj1.clone();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\singleton.ser"));
oos.writeObject(obj1);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\singleton.ser"));
MySingleton obj3 = (MySingleton) ois.readObject();
ois.close();
System.out.println("First Object :: "+obj1.getVal());
System.out.println("Clone Object :: "+obj2.getVal());
System.out.println("Serialized Object :: "+obj3.getVal()+"\n\n");
// Changing value in Object 3
obj3.setVal(100);
System.out.println("First Object :: "+obj1.getVal());
System.out.println("Clone Object :: "+obj2.getVal());
System.out.println("Serialized Object :: "+obj3.getVal()+"\n\n");
// Changing value in Object 3
obj2.setVal(1234);
System.out.println("First Object :: "+obj1.getVal());
System.out.println("Clone Object :: "+obj2.getVal());
System.out.println("Serialized Object :: "+obj3.getVal());
Constructor constructor = MySingleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
MySingleton newInstance = (MySingleton) constructor.newInstance();
System.out.println("NEW INSTANCE : "+newInstance.getVal());
}catch (Exception e) {
System.out.println(e.getCause());
}
}
}
In above class we created the Object (obj1) by calling static getInstance() method.
Next we have cloned the same Object (obj1) to other Object (obj2), since we have @Overrided clone() method in our first class it will return same Instance which have initialized at first time and we are blocking the cloning the Object here.
Next we have serialized the Object (Obj1) into a file and then again we have deserialized the Object to (ob3).
Next we are changing the "val" value of Object (obj3) where we can see value changed in all 3 Objects in the Output and we can confirm that user can't create new Object through serializing.
Next we are changing the "val" value of Object (obj2) where same way value has changed in all 3 Objects in the Output and we can confirm that even by cloning user will same Object instead of new Object.
Last we have testing whether are able to create instance using java.lang.reflect.Constructor class. In that case we will get exception called InstanceAlreadyExistsException and new instance can't be created.
OUTPUT:
Inside Constructor..
First Object :: 739385266
Clone Object :: 739385266
Serialized Object :: 739385266
First Object :: 100
Clone Object :: 100
Serialized Object :: 100
First Object :: 1234
Clone Object :: 1234
Serialized Object :: 1234
Object already created....
javax.management.InstanceAlreadyExistsException
Hope you are clear now how to create fully Singleton class. Please drop your comments below.