单例模式的应用(2)

简介: 单例模式的应用(2)

三、反射破坏单例


一个单例对象创建好后,有时候需要将对象序列化然后写入磁盘,下次使用时再从磁盘中读对象进行反序列化,将其转换为内存对象。反序列化后的对象会重新分配内存,即重新创建。如果序列化的目标对象为单例对象,就违背了单例模式的初衷,相当于破坏了单例,来看一段代码:


public class Singleton {  
    private static class LazyHolder {  
       private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
       return LazyHolder.INSTANCE;  
    }  
}  


//单例模式,通过反射获取实例


public class ReflectTest {
    public static void main(String[] args) {
        try {
            Class<?> clazz = Singleton.class;
            //获取该单例类的空构造器
            Constructor c = clazz.getDeclaredConstructor(null);
            //绕过私有权限
            c.setAccessible(true);
            Object instance1 = c.newInstance();
            Object instance2 = c.newInstance();
            System.out.println(instance1);
            System.out.println(instance2);
            System.out.println(instance1 == instance2);
        }catch (Exception e){
            e.printStackTrace();
        }
    }


通过反射获得单例类的构造函数,由于该构造函数是private的,通过setAccessible(true)指示反射的对象在使用时应该取消 Java 语言访问检查,使得私有的构造函数能够被访问,这样使得单例模式失效。


//自认为史上最牛的单例模式的实现方式
public class Singleton {  
    //使用LazyHolder的时候,默认会先初始化内部类
    //如果没使用,则内部类不加载的
    private static class LazyHolder {  
       private static final Singleton INSTANCE = new Singleton();  
    }  
    // 每一个关键字都不是多余的,static是为了使单例的空间共享,保证这个放啊不会被重写、重载
    private Singleton (){
       if(LazyHolder.INSTANCE!=null){
       //在返回结构以前,一定会先加载内部类
           throw new RuntimeException("不允许创建多个实例!");
       }
    }  
    // 默认不加载
    public static final Singleton getInstance() {  
       return LazyHolder.INSTANCE;  
    }  
}  


四、序列化破坏单例

一个单例对象创建好后,有时候需要将对象序列化然后写入磁盘,下次使用时再从磁盘中读取对象,并进行反序列化,将其转化为内存对象。反序列化后的对象会重新分配内存,即重新创建。如果序列化的目标对象为单例对象,就违背了单例模式的初衷,相当于违背了单例模式。


public class SeriableSingleton implements Serializable {
    //序列化
    //把内存中对象的状态转换为字节码的形式
    //把字节码通过IO输出流,写到磁盘上
    //永久保存下来,持久化
    //反序列化
    //将持久化的字节码内容,通过IO输入流读到内存中来
    //转化成一个Java对象
    public  final static SeriableSingleton INSTANCE = new SeriableSingleton();
    private SeriableSingleton(){}
    public static SeriableSingleton getInstance(){
        return INSTANCE;
    }
}


public class SeriableSingletonTest {
    public static void main(String[] args) {
        SeriableSingleton s1 = null;
        SeriableSingleton s2 = SeriableSingleton.getInstance();
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("SeriableSingleton.obj");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(s2);
            oos.flush();
            oos.close();
            FileInputStream fis = new FileInputStream("SeriableSingleton.obj");
            ObjectInputStream ois = new ObjectInputStream(fis);
            s1 = (SeriableSingleton)ois.readObject();
            ois.close();
            System.out.println(s1);
            System.out.println(s2);
            System.out.println(s1 == s2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


从运行结果可以看出,反序列化后的对象和手动创建的对象是不一致的,实例化了两次,违背了单例设计模式的初衷。那么,我们如何保证在序列化的情况下,也能够实现单例模式呢,其实很简单,只要增加readResolve()方法即可。


public class SeriableSingleton implements Serializable {
    //序列化
    //把内存中对象的状态转换为字节码的形式
    //把字节码通过IO输出流,写到磁盘上
    //永久保存下来,持久化
    //反序列化
    //将持久化的字节码内容,通过IO输入流读到内存中来
    //转化成一个Java对象
    public  final static SeriableSingleton INSTANCE = new SeriableSingleton();
    private SeriableSingleton(){}
    public static SeriableSingleton getInstance(){
        return INSTANCE;
    }
    private Object readResolve(){ return INSTANCE;}
}



目录
相关文章
|
7月前
|
设计模式 安全 测试技术
【C++】—— 单例模式详解
【C++】—— 单例模式详解
|
6月前
|
设计模式 安全 Java
单例模式分享
单例模式分享
30 0
|
7月前
|
C++
【C++ 单例模式】
【C++ 单例模式】
|
7月前
|
设计模式 安全
【单例模式】—— 每天一点小知识
【单例模式】—— 每天一点小知识
|
设计模式 Java Spring
什么场景要使用单例模式,什么场景不能使用?
经常有小伙伴问我,设计模式学了这么久,每次看到概念也都能理解。但是,就是不知道怎么用,在哪里能用?我告诉大家,设计模式,不是为了要用而用的,而是作为前人总结下来的经验,等到哪天需要用的时候,你能想起来为你所用。
110 0
|
设计模式 C#
C# 机房重构单例模式
C# 机房重构单例模式
73 0
|
安全 Java
单例模式很简单
《基础系列》
123 0
单例模式很简单
|
存储 安全 调度
单例模式的简单介绍
单例模式的简单介绍
|
设计模式 安全 前端开发
关于单例模式,你应该了解这些
关于单例模式,你应该了解这些
关于单例模式,你应该了解这些
|
SQL 设计模式 安全
单例模式详解
单例模式详解
250 0
单例模式详解