java设计模式一创建型模式一单例模式一序列化破坏单例模式和其解决方法

本文探讨了如何通过序列化方式破坏Java中的单例模式,并提供了使用readResolve()方法来解决这个问题。在序列化和反序列化过程中,如果不采取措施,将可能导致单例模式失效。通过在Singleton类中添加readResolve()方法,可以确保在反序列化时返回相同的单例实例,从而保护单例模式不被破坏。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

想要破坏单例模式,可以在定义的单例类Singleton创建多个对象.枚举方式除外,还有两种方式,序列化和反射.我们先看序列化.不知道序列化的可以点击以下链接进行学习,博主讲了很详细.http://t.csdn.cn/2oNXN

单例模式代码:

import java.io.Serializable;

public class Singleton implements Serializable {

    //私有构造方法
    private Singleton(){

    }
    //定义一个静态内部类
    private static class SingletonHolder{
        //在内部类中声明并初始化外部类的对象
        private static final Singleton INSTANCE = new Singleton();
    }
    //提供公共的访问方式
    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

测试类,序列化破坏单例模式

代码演示:

public class Client {
    public static void main(String[] args) throws Exception{
        writeObject2File();//注意此处,先注释下面两个readObjectFromFile()方法,然后在运行
        readObjectFromFile();//writeObject2File(),运行完后在注释writeObject2File(),取消
        readObjectFromFile();//两个readObjectFromFile()方法的注释,再运行
//从文件中读数据(对象)
public static void readObjectFromFile() throws Exception{
    //1,创建对象输入流对象
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\15722\\Desktop\\a.txt"));
    //2,读取对象
    Singleton instance = (Singleton) ois.readObject();

    System.out.println(instance);

    //释放资源
    ois.close();
}
public static void writeObject2File() throws Exception{
        //1,获取Singleton对象
        Singleton instance = Singleton.getInstance();
        //2,创建对象输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\15722\\Desktop\\a.txt"));
        //3,写对象
        oos.writeObject(instance);
        //4,释放资源
        oos.close();
    }
}

//这里的"C:\\Users\\15722\\Desktop"为桌面路径(根据自己的桌面路径进行更改),上面代码目的是在桌面创建一个a.txt文件

运行后我们桌面会生成一个a.txt文件,控制台输出如下:

同一个readObjectFromFile(),输出了两种结果(地址值不一样),表示两次从文件读到的对象不是同一个,已经破坏了单例模式.

序列化、反序列化破坏单例模式的解决方法:

在定义的Singleton类中添加readResolve()方法,在反序列化时被调用.如果定义了这个方法,就返回这个方法的值,如果没有定义,则返回新new出来的对象.

单例模式代码:

import java.io.Serializable;

public class Singleton implements Serializable {

    //私有构造方法
    private Singleton(){

    }
    //定义一个静态内部类
    private static class SingletonHolder{
        //在内部类中声明并初始化外部类的对象
        private static final Singleton INSTANCE = new Singleton();
    }
    //提供公共的访问方式
    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }

    //当进行反序列化时,会自动调用该方法,将该方法的返回值直接返回
    public Object readResolve(){
        return SingletonHolder.INSTANCE;
    }
}

跟上面相比,多了个新定义的readResolve()方法.

测试类代码:

public class Client {
    public static void main(String[] args) throws Exception{
        writeObject2File();//注意此处,先注释下面两个readObjectFromFile()方法,然后在运行
        readObjectFromFile();//writeObject2File(),运行完后在注释writeObject2File(),取消
        readObjectFromFile();//两个readObjectFromFile()方法的注释,再运行
//从文件中读数据(对象)
public static void readObjectFromFile() throws Exception{
    //1,创建对象输入流对象
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\15722\\Desktop\\a.txt"));
    //2,读取对象
    Singleton instance = (Singleton) ois.readObject();

    System.out.println(instance);

    //释放资源
    ois.close();
}
public static void writeObject2File() throws Exception{
        //1,获取Singleton对象
        Singleton instance = Singleton.getInstance();
        //2,创建对象输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\15722\\Desktop\\a.txt"));
        //3,写对象
        oos.writeObject(instance);
        //4,释放资源
        oos.close();
    }
}

根据代码注释所说的步骤,重新运行一遍代码,结果如下:

我们可以发现,这两次从文件读取的对象的结果(地址值)是一样的,说明我们已经防止了经过序列化、反序列化后破坏了单例模式.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值