今天在序列化反序列化的時候,發現單例模式竟然實作不了,
查了一下資料,發現反序列化由于使用了反射機制來建立一個新的對象,
導緻其并沒有受到單例模式的限制,今天做一個總結,以便後續查詢。
有興趣的可以從java.io.ObjectInputStream中的public final Object readObject()開始,
看一下jdk的源碼:
public final Object readObject()
throws IOException, ClassNotFoundException {
return readObject(Object.class);
}
private final Object readObject(Class<?> type)
throws IOException, ClassNotFoundException
{
if (enableOverride) {
return readObjectOverride();
}
if (! (type == Object.class || type == String.class))
throw new AssertionError("internal error");
// if nested read, passHandle contains handle of enclosing object
int outerHandle = passHandle;
try {
Object obj = readObject0(type, false);
handles.markDependency(outerHandle, passHandle);
ClassNotFoundException ex = handles.lookupException(passHandle);
if (ex != null) {
throw ex;
}
if (depth == 0) {
vlist.doCallbacks();
freeze();
}
return obj;
} finally {
passHandle = outerHandle;
if (closed && depth == 0) {
clear();
}
}
}
理論上,這應該是一個jdk内的bug,不過網上也給出的解決方案,
就是在實作單例模式的類中,新增一個Object readResolve()方法(注意:這不是重寫):
//the method can have private, protected and package-private access
private Object readResolve() throws ObjectStreamException{
return ourInstance; // ourInstance是該類中的靜态私有變量
}
大家可以看一下java.io.Serializable中對于Object readResolve()方法的描述:
具體的測試代碼,如下:
import java.io.Serializable;
import java.io.*;
/*
如何序列化單例模式?
*/
public class Solution implements Serializable {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Singleton instance = Singleton.getInstance();
ByteArrayOutputStream byteArrayOutputStream = serializeSingletonInstance(instance);
Singleton singleton = deserializeSingletonInstance(byteArrayOutputStream);
Singleton singleton1 = deserializeSingletonInstance(byteArrayOutputStream);
System.out.println("檢查 ourInstance:" + singleton.getInstance());
System.out.println("檢查 ourInstance:" + singleton1.getInstance());
System.out.println("=========================================================");
System.out.println("檢查 singleton:" + singleton);
System.out.println("檢查 singleton1:" + singleton1);
}
public static ByteArrayOutputStream serializeSingletonInstance(Singleton instance) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream);
oos.writeObject(instance);
oos.close();
return byteArrayOutputStream;
}
public static Singleton deserializeSingletonInstance(ByteArrayOutputStream byteArrayOutputStream) throws IOException, ClassNotFoundException {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream);
Singleton singleton = (Singleton) ois.readObject();
ois.close();
return singleton;
}
public static class Singleton implements Serializable {
private static Singleton ourInstance;
private Singleton() {
}
//新增一個Object readResolve()方法
private Object readResolve() throws ObjectStreamException{
return ourInstance;
}
public static Singleton getInstance() {
//synchronized (Singleton.class) {
if (ourInstance == null) {
ourInstance = new Singleton();
}
//}
return ourInstance;
}
}
}