第一章 简单工厂模式
第二章 工厂方法模式
第三章 抽象工厂模式
第四章 单例模式
第五章 破坏单例模式
文章目录
- Java设计模式浅析
- 一、反射破坏单例
- 示例代码
- 测试代码
- 注释结果
- 非注释结果
- 二、序列化破坏单例
- 示例代码
- 测试代码
- 注释结果
- 非注释结果
- 总结
上一章中单例模式的构造方法除了加上 private 关键字,没有做任何处理。 如果我们使用反射来调用其构造方法,在调用 getInstance() 方法, 应该有两个不同的实例。现在来看一段测试代码,以 LazyInnerClassSingleton 为例:示例代码
LazyInnerClassSingleton
public class LazyInnerClassSingleton { private LazyInnerClassSingleton() { } // 注意关键字final,保证方法不被重写和重载 public static final LazyInnerClassSingleton getInstance() { // 在返回结果之前,会先加载内部类 // 调用内部类属性 return LazyHolder.INSTANCE; } // 默认不加载 //LazyHolder 单例持有者 // 最终返回 LazyHolder 的属性 LAZY 的引用,最终把引用返回到客户端 private static class LazyHolder { private static final LazyInnerClassSingleton INSTANCE = new LazyInnerClassSingleton(); } }
测试代码
LazyInnerClassSingletonTest
public class LazyInnerClassSingletonTest { public static void main(String[] args) { try { // 声明一个Class对象 该对象是LazyInnerClassSingleton Class> clazz = LazyInnerClassSingleton.class; // 通过反射获取私有的构造方法 Constructor c = clazz.getDeclaredConstructor(new Class[]{}); // 强制访问 --private 私有成员变量 设置强制访问 c.setAccessible(true); // 暴力初始化 Object o1 = c.newInstance(); // 调用了两次构造方法,相当于“new”了两次 Object o2 = c.newInstance(); System.out.println(o1 == o2); //System.out.println(o1); } catch (Exception e) { e.printStackTrace(); } } }注释结果 非注释结果 二、序列化破坏单例
一个单例对象创建好后,有时候需要将对象序列化然后写入磁盘, 下次使用时再从磁盘中读取对象并进行反序列化,将其转化为内存对象。 反序列化后的对象会重新分配内存,即重新创建。如果序列化的目标对象为单例对象, 就违背了单例模式的初衷,相当于破坏了单例,来看一段代码:示例代码
SeriableSingleton
public class SeriableSingleton implements Serializable { // 序列化就是把内存中的状态通过转换成字节码的形式 // 从而转换一个 I/O 流,写入其他地方(可以是磁盘、网络 I/O) // 内存中的状态会永久保存下来 // 反序列化就是将已经持久化的字节码内容转换为I/O流 // 通过I/O流的读取,进而将读取的内容转换为Java对象 // 在转换过程中会重新创建对象new private SeriableSingleton(){} private static final SeriableSingleton instance = new SeriableSingleton(); public static SeriableSingleton getInstance(){ return instance; } //避免序列化破坏单例 }测试代码
SeriableSingletonTest
import java.io.*; 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(); fis.close(); System.out.println(s1 == s2); } catch (Exception e) { e.printStackTrace(); } } }注释结果 非注释结果
//避免序列化破坏单例
readResolve 详解见
https://www.yuque.com/yinjianwei/vyrvkf/uxggg3#lqkFI
反射会创了多个实例,最后经过判断没有返回新的实例,创建多个实例但是并没有使用。