序列化对单例模式的破坏

单例模式举例

单例模式举例,代码如下

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方法,如果包含,就会通过反射调用该方法,而我们通过重写该方法,来保证单例不被反序列化破坏。

示例代码

posted @ 2020-07-12 14:48  田青2011  阅读(108)  评论(0)    收藏  举报