当前位置: 首页 > news >正文

破坏单例模式--存在的问题---问题的解决

目录

破坏单例模式--存在的问题---问题的解决

 问题演示

破坏单例模式:

序列化

反射

序列化反序列化:

代码:

运行结果:

反射  

代码:

运行结果:

问题的解决

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

代码: 

运行结果:

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

代码:

运行结果:

JDK源码解析-Runtime类

Runtime类就是使用的单例设计模式。


破坏单例模式--存在的问题---问题的解决

  •  问题演示

    • 破坏单例模式:

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

  • 序列化

  • 反射

  • 序列化反序列化:

    • 代码:

Singleton类:

package com.dong.demo;import java.io.Serializable;public class Singleton implements Serializable {public Singleton() {}private static class  singletonHolder{private static final Singleton INSTANCE=new Singleton();}public static Singleton getInstance(){return singletonHolder.INSTANCE;}
}

Client类:

package com.dong.demo;import java.io.*;public class Client {public static void main(String[] args) throws IOException, ClassNotFoundException {// writeObject2File();readObject1File();readObject1File();}//此文件读取数据(对象)public static void readObject1File() throws IOException, ClassNotFoundException {//创建文件输出流对象ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:\\蓝桥杯\\设计模式作业\\530\\a.txt"));//读取对象Singleton singleton = (Singleton) ois.readObject();System.out.println(singleton);//释放资源ois.close();}//从文件中写数据(对象)public static void writeObject2File() throws IOException {//获取Singleton对象Singleton singleton=Singleton.getInstance();//创建对象输出流对象ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:\\蓝桥杯\\设计模式作业\\530\\a.txt"));//写对象oos.writeObject(singleton);//释放资源oos.close();}
}
  • 运行结果:

两对象不一样,因此,序列化破坏了单例模式。

表明序列化和反序列化已经破坏了单例设计模式。

  • 序列化会破坏单例模式的原因是在反序列化的过程中,会通过构造器重新创建一个新的对象。反序列化的过程是将二进制数据解码为Java对象,这个过程会创建一个新的对象,并不会保留旧对象的状态。因此,如果使用序列化和反序列化来实现单例模式,就可能破坏单例模式的唯一性。
  • 在上述代码中,每次读取对象时都会创建一个新对象并返回,与最初创建的对象并不相同。具体原因是:在Singleton类中定义了私有的构造方法,使得无法在外部调用构造方法创建对象,而在内部通过静态内部类singletonHolder的方式创建Singleton的唯一实例,并将该实例赋值给静态final变量INSTANCE。但是,当通过反序列化的方式创建对象时,虚拟机会自动调用Singleton类的无参构造方法创建一个新的对象,从而导致创建了多个不同的实例,打破了Singleton模式的设计初衷。

  • 反射  

代码:

Singleton类:

package com.dong.demo002;import java.io.Serializable;public class Singleton implements Serializable {public Singleton() {}private static class  singletonHolder{private static final Singleton INSTANCE=new Singleton();}public static Singleton getInstance(){return singletonHolder.INSTANCE;}
}

Client类:  

package com.dong.demo002;import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;/*** 反射破坏单例模式*/
public class Client {public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//Singleton.class.getDeclaredConstructor().setAccessible(true);//获取Singleton的字节码对象Class singletonClass = Singleton.class;//获取无参构造方法对象Constructor cons = singletonClass.getDeclaredConstructor();//取消范文检查cons.setAccessible(true);//创建Singleton对象Singleton s1 = (Singleton) cons.newInstance();Singleton s2= (Singleton) cons.newInstance();System.out.println(s1==s2);}
}

运行结果:

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

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

问题的解决

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

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

代码: 

Singleton类:

package com.dong.demo001;import java.io.Serializable;public class Singleton implements Serializable {public 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类:【不变】

package com.dong.demo001;import java.io.*;public class Client {public static void main(String[] args) throws IOException, ClassNotFoundException {// writeObject2File();readObject1File();readObject1File();}//此文件读取数据(对象)public static void readObject1File() throws IOException, ClassNotFoundException {//创建文件输出流对象ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:\\蓝桥杯\\设计模式作业\\530\\a.txt"));//读取对象Singleton singleton = (Singleton) ois.readObject();System.out.println(singleton);//释放资源ois.close();}//从文件中写数据(对象)public static void writeObject2File() throws IOException {//获取Singleton对象Singleton singleton=Singleton.getInstance();//创建对象输出流对象ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("D:\\蓝桥杯\\设计模式作业\\530\\a.txt"));//写对象oos.writeObject(singleton);//释放资源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;
}
  • 反射方式破解单例的解决方法

代码:

package com.dong.demo002;import java.io.Serializable;public class Singleton implements Serializable {private static boolean flag=false;public Singleton() {synchronized (Singleton.class) {if (flag) {throw new RuntimeException("不能创建多个对象!!!!!!");}flag = true;}}private static class  singletonHolder{private static final Singleton INSTANCE=new Singleton();}public static Singleton getInstance(){return singletonHolder.INSTANCE;}
}
package com.dong.demo002;import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;/*** 反射破坏单例模式*/
public class Client {public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//Singleton.class.getDeclaredConstructor().setAccessible(true);//获取Singleton的字节码对象Class singletonClass = Singleton.class;//获取无参构造方法对象Constructor cons = singletonClass.getDeclaredConstructor();//取消范文检查cons.setAccessible(true);//创建Singleton对象Singleton s1 = (Singleton) cons.newInstance();Singleton s2= (Singleton) cons.newInstance();System.out.println(s1==s2);}
}

运行结果:

 或:

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

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

说明:

这种方式比较好理解。当通过反射方式调用构造方法进行创建创建时,直接抛异常。不运行此中操作。


JDK源码解析-Runtime类

Runtime类就是使用的单例设计模式。

  1. 通过源代码查看使用的是哪儿种单例模式

从上面源代码中可以看出Runtime类使用的是饿汉式(静态属性)方式来实现单例模式的。

2.使用Runtime类中的方法  

public class RuntimeDemo {public static void main(String[] args) throws IOException {//获取Runtime类对象Runtime runtime = Runtime.getRuntime();//返回 Java 虚拟机中的内存总量。System.out.println(runtime.totalMemory());//返回 Java 虚拟机试图使用的最大内存量。System.out.println(runtime.maxMemory());//创建一个新的进程执行指定的字符串命令,返回进程对象Process process = runtime.exec("ipconfig");//获取命令执行后的结果,通过输入流获取InputStream inputStream = process.getInputStream();byte[] arr = new byte[1024 * 1024* 100];int b = inputStream.read(arr);System.out.println(new String(arr,0,b,"gbk"));}
}

相关文章:

破坏单例模式--存在的问题---问题的解决

目录 破坏单例模式--存在的问题---问题的解决 问题演示 破坏单例模式: 序列化 反射 序列化反序列化: 代码: 运行结果: 反射 代码: 运行结果: 问题的解决 序列化、反序列方式破坏单例模式的解…...

SpringCloud微服务踩坑系列-java.lang.IllegalStateException

异常如下: 2023-05-24 08:47:10.764 ERROR 118400 --- [nio-8084-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exceptio…...

Linux-地址空间

文章目录 问题引入操作系统宏观认识操作系统与进程程序地址空间进程地址空间问题解释 问题引入 在Linux操作系统中、vim编译器下,出现了变量同地址但不同值的现象。 下面以解释该现象产生的原因为主线,在过程中学习Linux操作系统的知识。 运行代码展示…...

【EKS】基于Amazon EKS搭建kubernetes集群

文章目录 前言 | 亚马逊云科技 re:Invent前沿资讯一、介绍篇🎨什么是AWS 云计算什么是Amazon EKS 二、部署篇🔨1、创建集群VPC2、创建集群子网3、创建IGW网关4、创建路由表与子网绑定5、EKS集群创建6、创建kubeconfig配置文件7、添加计算节点组8、查看EK…...

Tomcat安装与启动和配置

目录 Tomcat 简介 Tomcat 安装 Tomcat 启动和配置 文件夹作用 启动,关闭Tomcat; 常见问题 配置 环境变量 IDEA中配置Tomcat Tomcat 简介 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在…...

ruoyi-vue版本(十八)创建自己的项目,使用若依里面的技术,多数据源的实现

目录 1 创建自己的项目2 连接MySQL数据库(多数据源)2.1 若依实现多数据源2.1.1 主要思想2.2 第三方的依赖的实现1 创建自己的项目 1 创建一个空文件夹 2 idea 里面创建项目...

C++-stack题型->最小栈,栈的压入与弹出,逆波兰表达式

目录 最小栈 栈的压入与弹出 逆波兰表达式 最小栈 155. 最小栈 - 力扣(Leetcode) 设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。void …...

【计算机网络实验】BGP和OSPF协议仿真实验

实验内容  BGP和OSPF协议仿真实验 实验目的 (1)学习BGP协议的配置方法; (2)验证BGP协议的工作原理; (3)掌握网络自治系统的划分方法; (4)验证…...

提升日期处理效率:day.js 实战经验分享

theme: smartblue 本文简介 点赞 关注 收藏 学会了 本文主要介绍我在工作中使用 day.js 较多的方法。本文并不能代替 day.js 官方文档,日常工作中该查文档的还是要查文档。本文是写给刚接触 day.js 的工友,让这部分工友能更顺利上手 day.js。本文不涉…...

mysql中的count(1)、count(*)、count(id)哪个更快?

今天和大家聊一下mysql中的count()方法 我们日常开发中,经常会用到count()命令,有的人用count(*),有的人用count(1),还有的人用count(id),那么这几种写法都有什么区别呢?哪种方法效率更高呢?今…...

cf1750E Bracket Cost

前言: 好久没训练了,来做道计数题找找感觉。**期末毁我青春 大意: 定义对于一个括号串 s的值,为通过最小次数以下操作使 s 实现括号匹配的操作次数。 选择一个子串,循环右移一位。在任意一个位置插入一个任意括号。 求一个括…...

Vue+springboot医院住院挂号登记收费系统7ui9s

医院信息管理系统的开发过程中,采用B / S架构,主要使用java语言进行开发,结合最新流行的springboot框架。使用Mysql数据库和idea开发环境。该医院信息管理系统包括用户、医生和管理员。其主要功能包括用户管理、医生管理、医生信息管理、预约…...

大前端之Koa2学习

Koa2框架介绍 Koa2是一个基于Node.js的Web框架,它使用了ES6的语法和async/await特性,使得编写异步代码更加简单和优雅。Koa2的核心思想是中间件,它允许开发者将应用程序拆分成小的、可重用的部分,从而使得代码更加模块化和易于维…...

Qml实现Dock浮动、停靠功能

纯Qml实现Dock浮动、停靠功能 效果展示github地址:介绍环境Demo代码参数说明API说明 效果展示 Qml Dock效果演示 github地址: https://github.com/longtwilight/QmlDock 介绍 这是一个使用纯qml实现的Dock组件,它支持停靠、浮动、窗体分离、窗体独立、大小调整等…...

最新版本 Stable Diffusion 开源 AI 绘画工具之微调模型篇

✨ 目录 🎈 模型种类🎈 变分自动编码器 / VAE🎈 美学梯度 / Aesthetic Gradients🎈 大型语言模型的低阶自适应 / LoRA🎈 超网络模型 / Hypernetwork🎈 微调模型 / LyCORIS 🎈 模型种类 当你打开…...

路径规划算法:基于哈里斯鹰优化的路径规划算法- 附代码

路径规划算法:基于哈里斯鹰优化的路径规划算法- 附代码 文章目录 路径规划算法:基于哈里斯鹰优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要:本文主要介绍利用智能优化…...

Web 应用程序防火墙 (WAF) 相关知识介绍

Web应用程序防火墙 (WAF) 如何工作? Web应用防护系统(也称为:网站应用级入侵防御系统。英文:Web Application Firewall,简称:WAF)。利用国际上公认的一种说法:Web应用防火墙是通过执…...

docker快速部署hue+hue集成hive

首先需要安装hive,hive的安装在HIVE的安装与配置_EEEurekaaa!的博客-CSDN博客 安装完成之后,使用脚本命令启动hdfs和hive的相关服务。 一、安装docker # 安装yum-config-manager配置工具 $ yum -y install yum-utils # 设置yum源 $ yum-co…...

基于java SpringBoot和Vue uniapp的校园信息交流小程序

随着信息社会的网络化和计算机科学的广泛普及和迅速普及应用,具有综合智能的我国校园信息教育网络已成为推动中小学科学教育及其实践科学发展的信息技术手段。迅速推进了信息化改革,改善了高校信息交流的网络环境,提高了信息教育平台的管理水…...

数据包伪造替换、会话劫持、https劫持之探索和测试

(一)数据包替换攻击 该攻击过程如下:伪造服务器响应客户端的数据包。监听客户端的数据包,用预先伪造的数据包,伪装成服务器返回的数据发送给客户端。 因为攻击者跟目标在同一个局域网,所以攻击者发送的数…...

正则表达式集合

目录 一、校验数字的表达式 1. 数字 2. n位的数字 3. 至少n位的数字 4. m-n位的数字 5. 零和非零开头的数字 6. 非零开头的最多带两位小数的数字 7. 带1-2位小数的正数或负数 8. 正数、负数、和小数 9. 有两位小数的正实数 10. 有1~3位小数的正实数 11. 非零的正整…...

Django框架中models对象转换为json的方法

在django框架中输出api接口时一般都是输出json数据但是通过orm获取的数据库数据一般都是object所以需要转换成json数据,一般有一下3种情况 1.models对象使用“all()”时 from django.http import HttpResponse from django.core import serializers from TestMode…...

利用Servlet编写第一个“hello world“

利用Servlet编写第一个"hello world" 🔎创建 Maven 项目🔎引入依赖🔎创建目录🔎编写代码🔎打包代码🔎部署🔎程序验证🔎结尾 🔎创建 Maven 项目 Maven 是一个构…...

python 爬虫之js逆向爬虫详解

随着网站前端技术的不断发展,越来越多的网站采用JS进行渲染,并加上了一些反爬机制,导致传统的爬虫技术有些力不从心。本文将为大家介绍如何进行JS逆向爬虫,并且不少于1000字。 一、JS逆向爬虫的介绍 JS逆向是一种分析反爬机制的…...

SpringBoot:WebSocket实现消息撤回、图片撤回

下面只是讲述一下实现思路,代码基本没有哈!有时间单独发表一篇关于websocket的相关操作的博客。 1. 消息撤回、图片撤回 个人觉得关于撤回,需要下述几个过程: 发送的消息的标签上可以定义一个属性,这个属性的值应该是…...

输出指定日期区间内的所有天、周、月

部分方法需要依赖hutool工具包。 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>4.5.10</version> </dependency>需求&#xff1a;输出2023-04-17到2023-05-23期间所有的天、周、月。…...

【线性规划模型】

线性规划模型&#xff1a;原理介绍和预测应用 引言 线性规划是运筹学中一种重要的数学优化方法&#xff0c;被广泛应用于各个领域&#xff0c;包括工业、经济、物流等。 线性规划模型的原理 线性规划模型的目标是在一组线性约束条件下&#xff0c;寻找一组变量的最优解&…...

android 12.0卸载otg设备开机不加载otg设备

1.概述 在12.0定制化开发过程中,客户有功能需求,通过系统属性值控制是否加载挂载otg设备,当设置为卸载模式时,要求不能挂载otg设备,开机也不能挂载otg设备 2.卸载otg设备开机不加载otg设备的核心代码 frameworks/base/services/core/java/com/android/server/StorageMan…...

通过 Wacom 的 Project Mercury 提高远程办公效率

过去几年中&#xff0c;我们的工作方式发生了翻天覆地的变化。疫情加快了对远程办公和协作的采纳&#xff0c;导致人们更加依赖技术来联系团队和提高工作效率。 但是&#xff0c;那些依靠专门硬件和软件来完成工作的创作者呢&#xff1f;艺术家、设计师和开发人员需要使用专门…...

Linux-0.11 文件系统namei.c详解

Linux-0.11 文件系统namei.c详解 模块简介 namei.c是整个linux-0.11版本的内核中最长的函数&#xff0c;总长度为700行。其核心是namei函数&#xff0c;即根据文件路径寻找对应的i节点。 除此以外&#xff0c;该模块还包含一些创建目录&#xff0c;删除目录&#xff0c;创建目…...