破坏单例模式:

使上面定义的单例类(Singleton)可以创建多个对象,枚举方式除外。

有两种方式,分别是序列化和反射



序列化反序列化

Singleton类:

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;}
}

Test类:

public class Test {public static void main(String[] args) throws Exception {//往文件中写对象//writeObject2File();//从文件中读取对象Singleton s1 = readObjectFromFile();Singleton s2 = readObjectFromFile();//判断两个反序列化后的对象是否是同一个对象System.out.println(s1 == s2);}private static Singleton readObjectFromFile() throws Exception {//创建对象输入流对象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Think\\Desktop\\a.txt"));//第一个读取Singleton对象Singleton instance = (Singleton) ois.readObject();return instance;}public static void writeObject2File() throws Exception {//获取Singleton类的对象Singleton instance = Singleton.getInstance();//创建对象输出流ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Think\\Desktop\\a.txt"));//将instance对象写出到文件中oos.writeObject(instance);}
}

上面代码运行结果是false,表明序列化和反序列化已经破坏了单例设计模式。



反射

Singleton类:

package com.itheima.pattern.singleton.demo8;public class Singleton {//私有构造方法private Singleton() {}private static volatile Singleton instance;//对外提供静态方法获取该对象public static Singleton getInstance() {if(instance != null) {return instance;}synchronized (Singleton.class) {if(instance != null) {return instance;}instance = new Singleton();return instance;}}
}

Client.java

package com.itheima.pattern.singleton.demo8;import java.lang.reflect.Constructor;/*** @version v1.0* @ClassName: Client* @Description:*      测试使用反射破坏单例模式* @Author: dym*/
public class Client {public static void main(String[] args) throws Exception {//1,获取Singleton的字节码对象Class clazz = Singleton.class;//2,获取无参构造方法对象Constructor cons = clazz.getDeclaredConstructor();//3,取消访问检查cons.setAccessible(true);//4,创建Singleton对象Singleton s1 = (Singleton) cons.newInstance();Singleton s2 = (Singleton) cons.newInstance();System.out.println(s1 == s2); //如果返回的是true,说明并没有破坏单例模式,如果是false,说明破坏了单例模式}
}

上面代码运行结果是false,表明序列化和反序列化已经破坏了单例设计模式

注意:枚举方式不会出现这两个问题。



问题的解决

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

    在Singleton类中添加readResolve()方法,在反序列化时被反射调用

                 如果定义了这个方法,就返回这个方法的值,如果没有定义,则返回新new出来的对象。

Singleton类:

package com.itheima.pattern.singleton.demo7;import java.io.Serializable;/*** @version v1.0* @ClassName: Singleton* @Description: 静态内部类方式* * @Author: dym*/
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;}}

Client.java

package com.itheima.pattern.singleton.demo7;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;/*** @version v1.0* @ClassName: Client* @Description:*      测试使用序列化破坏单例模式**      桌面路径: C:\Users\Think\Desktop* * @Author: dym*/
public class Client {public static void main(String[] args) throws Exception {
//        writeObject2File();readObjectFromFile();readObjectFromFile();}//从文件读取数据(对象)public static void readObjectFromFile() throws Exception {//1,创建对象输入流对象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Administrator\\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\\Administrator\\Desktop\\a.txt"));//3,写对象oos.writeObject(instance);//4,释放资源oos.close();}
}



源码解析:

ObjectInputStream类

public final Object readObject() throws IOException, ClassNotFoundException{...// if nested read, passHandle contains handle of enclosing objectint outerHandle = passHandle;try {Object obj = readObject0(false);//重点查看readObject0方法.....
}private Object readObject0(boolean unshared) throws IOException {...try {switch (tc) {...case TC_OBJECT:return checkResolve(readOrdinaryObject(unshared));//重点查看readOrdinaryObject方法...}} finally {depth--;bin.setBlockDataMode(oldMode);}
}private Object readOrdinaryObject(boolean unshared) throws IOException {...//isInstantiable 返回true,执行 desc.newInstance(),通过反射创建新的单例类,obj = desc.isInstantiable() ? desc.newInstance() : null; ...// 在Singleton类中添加 readResolve 方法后 desc.hasReadResolveMethod() 方法执行结果为trueif (obj != null && handles.lookupException(passHandle) == null && desc.hasReadResolveMethod()) {// 通过反射调用 Singleton 类中的 readResolve 方法,将返回值赋值给rep变量// 这样多次调用ObjectInputStream类中的readObject方法,继而就会调用我们定义的readResolve方法,所以返回的是同一个对象。Object rep = desc.invokeReadResolve(obj);...}return obj;
}


反射方式破解单例的解决方法

public class Singleton {//私有构造方法private Singleton() {/*反射破解单例模式需要添加的代码*/if(instance != null) {throw new RuntimeException();}}private static volatile Singleton instance;//对外提供静态方法获取该对象public static Singleton getInstance() {if(instance != null) {return instance;}synchronized (Singleton.class) {if(instance != null) {return instance;}instance = new Singleton();return instance;}}
}

或者是这种方式

package com.itheima.pattern.singleton.demo8;/*** @version v1.0* @ClassName: Singleton* @Description: 静态内部类方式* * @Author: dym*/
public class Singleton {private static boolean flag = false;//私有构造方法private Singleton() {synchronized (Singleton.class) {//判断flag的值是否是true,如果是true,说明非第一次访问,直接抛一个异常,如果是false的话,说明第一次访问if (flag) {throw new RuntimeException("不能创建多个对象");}//将flag的值设置为trueflag = true;}}//定义一个静态内部类private static class SingletonHolder {//在内部类中声明并初始化外部类的对象private static final Singleton INSTANCE = new Singleton();}//提供公共的访问方式public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
}

Client.java

package com.itheima.pattern.singleton.demo8;import java.lang.reflect.Constructor;/*** @version v1.0* @ClassName: Client* @Description:*      测试使用反射破坏单例模式* * @Author: dym*/
public class Client {public static void main(String[] args) throws Exception {//1,获取Singleton的字节码对象Class clazz = Singleton.class;//2,获取无参构造方法对象Constructor cons = clazz.getDeclaredConstructor();//3,取消访问检查cons.setAccessible(true);//4,创建Singleton对象Singleton s1 = (Singleton) cons.newInstance();Singleton s2 = (Singleton) cons.newInstance();System.out.println(s1 == s2); //如果返回的是true,说明并没有破坏单例模式,如果是false,说明破坏了单例模式}
}

单例模式存在的问题——破坏单例模式,序列化和反射相关推荐

  1. 单例设计模式-序列化破坏单例模式原理解析及解决方案

    越来越成熟了,那是不是坚不可摧的呢,现在我们就要用序列号和反序列化来破坏单例模式,后面也会重点讲一下原理,好好听,让我们来一起破坏单例模式吧,首先还是来到Test类里边 package com.lea ...

  2. 单例设计模式 序列化破坏单例模式原理解析及解决方案?

    单例设计模式 序列化破坏单例模式原理解析及解决方案? 序列化和反序列化 反射的破坏

  3. 单例模式破坏单例模式

    什么是单例模式 经典设计模式又分23种,也就是GoF 23 总体分为三大类: 创建型模式 结构性模式 行为型模式 百度百科: 单例模式,属于创建类型的一种常用的软件设计模式.通过单例模式的方法创建的类 ...

  4. java 反射 单例类_利用反射机制破坏单例模式

    简介 利用反射机制破坏了单例模式,这里以懒汉单例模式为例子进行操作. 之前利用反射也是改变了类中的private变量. 类中的private变量真的private么? 正常的单例模式的实现 这里采用了 ...

  5. 单例模式之饿汉式单例模式

    单例模式之饿汉式单例模式 单例模式三要素: 1.私有的静态属性,这主要是为了存储类唯一的实例 2.公共的静态方法,这主要是为了提供给外键生成获取单例的方法 3.用于限制类再次实例话的措施.一般会私有化 ...

  6. Java23种设计模式之单例模式的五种实现方式、反射破解单例模式、不能破解枚举单例模式详解

    源码链接(Gitee码云):https://gitee.com/oldou/javadesignpatterns 这里有我整理好的Java23种设计模式的源码以及博客教程,博客教程中介绍了Java23 ...

  7. 什么是单例模式?为什么要用单例模式?实现的几种方式?

    Python 中的单例模式 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实 ...

  8. c++ 单例模式_你真的了解单例模式吗

    今天我们来看一下单例模式,如何颠覆我们的认知. 先告诉大家单例模式有以下这些,我们来看看它是如何一步一步演化的吧! 饿汉式单例 懒汉式单例 注册式单例 本地线程单例 饿汉式单例 我们熟知的饿汉式单例是 ...

  9. iOS设计模式 ——单例模式详解以及严格单例模式注意点

    一.我们常用的单例有哪些? [[UIApplication sharedApplication] statusBarStyle];//系统中的单例模式,通过它获取到状态栏的style [NSNotif ...

最新文章

  1. vs2015添加管理员权限
  2. 推荐好用 Spring Boot 内置工具类
  3. 云级Key-value数据库大比较
  4. 五十七、Servlet工程和Tomcat
  5. javaserver_集成Spring和JavaServer Faces:改进的模板
  6. 分析深圳电信的新型HTTP劫持方式
  7. windows10风格 springboot mybatis 项目框架源码 shiro 集成代码生成器
  8. php能做什么程序,PHP 能做什么?
  9. win7的配置要求详解
  10. Android 跟 ios 测试有什么区别
  11. 软件测试中的43个功能测试点(上)
  12. AMD64(x86_64)架构abi文档:中
  13. 精华来了(含PPT) | 淘系技术嘉年华-杭州站
  14. python撩妹技能_干货必看 | 手把手教你用Python撩妹
  15. java写的家谱_关于java:家谱计划的逻辑
  16. vue中使用滚动到列表底部
  17. 基于混沌系统的文本加密算法研究(二)——经典混沌映射
  18. p_conc_request_id
  19. 程序员需要研究厚黑学吗
  20. 二手车电商三国杀,广告大战究竟该不该打?

热门文章

  1. vue开发搭建(npm安装 + vue脚手架安装)
  2. java中BigDecimal的常见用法
  3. Lodop导出图片和打印机无关,测试是否有关
  4. Linux中chown和chmod的区别和用法(转)
  5. UML Design Via Visual Studio-Sequence Diagram
  6. 解决AW2013用led_classdev_register()注册red但/sys/class/leds下看不到red的问题
  7. 开发资源库(repositiory)
  8. android boot.img 结构
  9. 区块链软件公司:区块链的发展现状
  10. NineImageForCircleFriends朋友圈九宫格