宁海县做企业网站/中央突然宣布一个大消息
目录
序列化、反序列化对单例的破坏
原因分析
解决方案及解析
序列化、反序列化对单例的破坏
单例模式是工作中高频使用的设计模式之一。单例模式可以确保内存中单例类只有一个实例,有效的减少了内存的开销,避免了类的重复创建和销毁。
序列化意义是将实现序列化的Java对象转换成字节序列 ,这些字节序列可以被保存在磁盘上,或者通过网络传输。以备以后重新恢复成原来的对象。
对于单例类使用序列化、反序列化操作时,会破坏单例(序列化前的对象和反序列化后得到的对象内存地址不同),演示如下:
import java.io.*;public class LazySingleTon implements Serializable {private LazySingleTon(){}public static LazySingleTon getInstance(){return InnerClass.lazySingleTon;}private static class InnerClass{private static LazySingleTon lazySingleTon = new LazySingleTon();}public static void main(String[] args) throws IOException, ClassNotFoundException {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("tempFile"));oos.writeObject(LazySingleTon.getInstance());File file = new File("tempFile");ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));LazySingleTon newInstance = (LazySingleTon) ois.readObject();//判断是否是同一个对象System.out.println(newInstance);System.out.println(LazySingleTon.getInstance());System.out.println(newInstance == LazySingleTon.getInstance());}}
运行结果:
com.rbac.console.singleton.LazySingleTon@2d38eb89
com.rbac.console.singleton.LazySingleTon@cc34f4d
false
运行结果显示通过序列化前后对象不同,表明单例已经被破坏了
原因分析
以不求甚解的姿势对底层源码进行分析一波
从ois.readObject()这个方法为入口,即ObjectInputStream类的readObject方法
找到readObject0方法中的switch片段,判断反序列化对象类型,此时对象类型是Object
返回值会调用readOrdinaryObject方法,readOrdinaryObject方法中的三目允许算符判断了对象是不是可实例化的,如果是可实例化的会通过newInstance()方法反射实例化一个新的对象,所以序列化前的对象和反序列化后得到的对象不同!
解决方案及解析
解决方案是在单例类中加一个readResolve方法
public class LazySingleTon implements Serializable {//其他方法,略/*** 解决序列化、反序列化破坏单例* @return*/public Object readResolve(){return getInstance();}}
再次运行main方法输出:
com.rbac.console.singleton.LazySingleTon@cc34f4d
com.rbac.console.singleton.LazySingleTon@cc34f4d
true
可以看到这次序列化前后对象一致,单例没有被破坏
那为什么加一个readResolve方法就能阻止单例被破坏呢?
在刚才分析的readOrdinaryObject方法有调用hasReadResolveMethod的判断,这个方法是验证目标类是否包含一个方法名为readResolve的方法,如果有就执行desc.invokeReadResolve,通过反射调用单例类的LazySingleTon的readResolve方法,即我们刚才加的readResolve方法,并将获得的对象返回,所以序列化前后对象相同!阻止了单例被破坏
文章内容参考自慕课网
设计模式学习友情链接:
单例模式的懒汉式为什么是线程不安全的,懒汉式如何实现线程安全
设计模式【创建型模式】
这位小可爱,如果觉得文章不错,请关注或点赞 (-__-)谢谢