欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

序列化、反序列化对单例的破坏、原因分析、解决方案及解析

程序员文章站 2024-01-02 23:07:34
...

目录

序列化、反序列化对单例的破坏

原因分析

解决方案及解析


序列化、反序列化对单例的破坏

单例模式是工作中高频使用的设计模式之一。单例模式可以确保内存中单例类只有一个实例,有效的减少了内存的开销,避免了类的重复创建和销毁。

序列化意义是将实现序列化的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());
    }
 }

运行结果:

aaa@qq.com
aaa@qq.com
false

运行结果显示通过序列化前后对象不同,表面单例已经被破坏了

原因分析

以不求甚解的姿势对底层源码进行分析一波

从ois.readObject()这个方法为入口,即ObjectInputStream类的readObject方法

序列化、反序列化对单例的破坏、原因分析、解决方案及解析

找到readObject0方法中的switch片段,判断反序列化对象类型,此时对象类型是Object

序列化、反序列化对单例的破坏、原因分析、解决方案及解析

返回值会调用readOrdinaryObject方法,readOrdinaryObject方法中的三目允许算符判断了对象是不是可实例化的,如果是可实例化的会通过newInstance()方法反射实例化一个新的对象,所以序列化前的对象和反序列化后得到的对象不同!

序列化、反序列化对单例的破坏、原因分析、解决方案及解析

解决方案及解析

解决方案是在单例类中加一个readResolve方法

public class LazySingleTon implements Serializable {
        //其他方法,略

        /**
         * 解决序列化、反序列化破坏单例
         * @return
         */
        public Object readResolve(){
            return getInstance();
        }
     }

再次运行main方法输出:

aaa@qq.com
aaa@qq.com
true

可以看到这次序列化前后对象一致,单例没有被破坏

那为什么加一个readResolve方法就能阻止单例被破坏呢?

在刚才分析的readOrdinaryObject方法有调用hasReadResolveMethod的判断,这个方法是验证目标类是否包含一个方法名为readResolve的方法,如果有就执行desc.invokeReadResolve,通过反射调用单例类的LazySingleTon的readResolve方法,即我们刚才加的readResolve方法,并将获得的对象返回,所以序列化前后对象相同!阻止了单例被破坏

序列化、反序列化对单例的破坏、原因分析、解决方案及解析

 

文章内容参考自慕课网                   

设计模式学习友情链接:

单例模式的懒汉式为什么是线程不安全的,懒汉式如何实现线程安全

设计模式【创建型模式】


这位小可爱,如果觉得文章不错,请关注或点赞    (-__-)谢谢

序列化、反序列化对单例的破坏、原因分析、解决方案及解析

 
相关标签: 源码分析

上一篇:

下一篇: