单例模式的应用(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;}
}



目录
相关文章
|
5天前
|
设计模式 安全 C#
C# 单例模式的多种实现
C# 单例模式的多种实现
|
1月前
|
C++
C++单例模式
C++中使用模板实现单例模式的方法,并通过一个具体的类A示例展示了如何创建和使用单例。
29 2
|
6月前
|
设计模式 安全
【单例模式】—— 每天一点小知识
【单例模式】—— 每天一点小知识
|
设计模式 安全 Java
单例模式的运用
单例模式的运用
44 0
|
设计模式 Java Spring
什么场景要使用单例模式,什么场景不能使用?
经常有小伙伴问我,设计模式学了这么久,每次看到概念也都能理解。但是,就是不知道怎么用,在哪里能用?我告诉大家,设计模式,不是为了要用而用的,而是作为前人总结下来的经验,等到哪天需要用的时候,你能想起来为你所用。
104 0
|
设计模式 前端开发
关于单例模式我所知道的
关于单例模式我所知道的
58 0
关于单例模式我所知道的
|
SQL 安全 Java
五种单例模式介绍
五种单例模式介绍
91 0
|
设计模式 缓存
我学会了,单例模式
单例模式属于创建型模式,这个类型的设计模式是将 对象的创建和使用解耦了,花式的去创建对象。
126 0
我学会了,单例模式
|
设计模式 数据库 Python
|
设计模式 安全 Java
回顾一下单例模式
回顾一下单例模式
120 0