序列化对单例模式的破坏
单例模式举例
单例模式举例,代码如下
public class Singleton {
private Singleton() {
}
public static Singleton getInstance() {
return SingleHolder.singleton;
}
private static class SingleHolder {
private static final Singleton singleton = new Singleton();
}
}
正常对象的获取,可以保持对象的单例存在
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2); //输出true
序列化对单例的破坏
代码如下
package com.tong.t20190713;
import java.io.*;
public class SingletonTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2); //输出true
//将对象序列化到文件中
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton"));
oos.writeObject(instance1);
oos.close();
//将文件反序列化到对象
File file = new File("singleton");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
Singleton instance3 = (Singleton) ois.readObject();
System.out.println(instance1 == instance3); //输出false
}
}
序列化破坏单例的原因
通过debug,跟踪反序列化的执行过程,关键代码如下
OjbectInputStream -> readOrdinaryObject(boolean unshared)

如图片所示,通过反射创建对象,而这也是原因所在,此处反序列化用的是该类的父类的无参构造函数来创建对象。
序列化破坏单例的解决办法
通过添加以下代码即可
private Object readResolve() {
return getInstance();
}
这个方法可以生效的原因,还是要看代码
ObjectInputStream -> readOrdinaryObject(boolean unshared)

反序列化的过程中,会检测该类是否包含readResolve方法,如果包含,就会通过反射调用该方法,而我们通过重写该方法,来保证单例不被反序列化破坏。

浙公网安备 33010602011771号