Consider I have a Singleton class defined as follows.
public class MySingleton implements Serializable{
private static MySingleton myInstance;
private MyS
Here below is my Singleton
class that implements Serializable
interface. Mark that it contains readResolve()
method also.
import java.io.Serializable;
public class Singleton implements Serializable {
private static Singleton singleton = new Singleton( );
public int i = 1;
private Singleton() { }
public static Singleton getInstance( ) {
return singleton;
}
public Object readResolve() {
return getInstance( );
}
public static void main(String[] args) {
Singleton s1 = getInstance();
System.out.println(s1.hashCode());
Singleton s2 = getInstance();
System.out.println(s2.hashCode());
}
}
Below is the class that will first serialize and then deserialize the above class. Here deserialization takes place two times, but both time only one instance will be created because of readResolve() method.
public class SingletonSerializableDemo {
static Singleton sing = Singleton.getInstance();
static Singleton s1 = null;
static Singleton s2 = null;
public static void main(String[] args) {
try {
FileOutputStream fileOut =
new FileOutputStream("E:/singleton.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(sing);
out.close();
fileOut.close();
System.out.println("Serialized data is saved");
FileInputStream fileIn1 = new FileInputStream("E:/singleton.ser");
FileInputStream fileIn2 = new FileInputStream("E:/singleton.ser");
ObjectInputStream in1 = new ObjectInputStream(fileIn1);
ObjectInputStream in2 = new ObjectInputStream(fileIn2);
s1 = (Singleton) in1.readObject();
s2 = (Singleton) in2.readObject();
System.out.println(s1.hashCode() + " "+ s1.i);
s1.i = 10;
System.out.println(s2.hashCode() + " "+ s2.i);
in1.close();
in2.close();
fileIn1.close();
fileIn2.close();
}catch(Exception i) {
i.printStackTrace();
}
}
}
And the output will be:
Serialized data is saved
21061094 1
21061094 10
Conclusion: Singleton class can also be serialized by keeping readResolve()
method in the Singleton class.
Singleton classes is just like a manager or controller and in general we do not want to save the state of any controller instead of the entity. Generally we need to save the object state of any entity not the controller.
Singleton is singleton for a single class loader not for multiple class loader. If a class is loaded in a classes loader then the other class loader will not know about it so it behaves like this.
Let say we have the following singleton class:
public class ConnectionFactory implements Serializable {
private static ConnectionFactory INSTANCE;
private ConnectionFactory() { }
public static ConnectionFactory getInstance() {
if (INSTANCE == null) {
synchronized(ConnectionFactory.class) {
if(INSTANCE == null)
INSTANCE = new ConnectionFactory();
}
}
return INSTANCE;
}
}
Now we have the main class like below for serialising and deserializing objects:
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
ConnectionFactory INSTANCE=ConnectionFactory.getInstance();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("connFactory.ser"));
oos.writeObject(INSTANCE);
oos.close();
// Here I am recreating the instance by reading the serialized object data store
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("connFactory.ser"));
ConnectionFactory factory1 = (ConnectionFactory) ois.readObject();
ois.close();
// I am recreating the instance AGAIN by reading the serialized object data store
ObjectInputStream ois2 = new ObjectInputStream(new FileInputStream("connFactory.ser"));
ConnectionFactory factory2 = (ConnectionFactory) ois2.readObject();
ois2.close();
// Let's see how we have broken the singleton behavior
System.out.println("Instance reference check->" +factory1.getInstance());
System.out.println("Instance reference check->" +factory2.getInstance());
System.out.println("=========================================================");
System.out.println("Object reference check->" + factory1);
System.out.println("Object reference check->" + factory2);
}
So if we execute above code we will get following behaviour: "it has created two objects and one static reference for INSTANCE. That means if we read the serialized format of a singleton object multiple times, we will create multiple objects. This is not what a singleton object is supposed to do. So can we avoid i?, Yes, we can."
To avoid multiple instances of singleton class we will use following method provided by serialization:
private Object readResolve() throws ObjectStreamException {
return INSTANCE;
}
This will prevent the creation of multiple instances of a singleton class.