返回顶部
首页 > 资讯 > 精选 >Java中怎么破坏单例方式
  • 717
分享到

Java中怎么破坏单例方式

2023-06-16 12:06:49 717人浏览 泡泡鱼
摘要

本篇内容介绍了“Java中怎么破坏单例方式”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!单例模式(Singleton Pattern)是 J

本篇内容介绍了“Java中怎么破坏单例方式”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。是一种创建型设计模式。他的定义为:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

单例模式一般体现在类声明中,单例的类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

但是其实,单例并不是完完全全安全的,也是有可能被破坏的。

以下,是一次面试现场的还原,之所以会聊到这个话题,是因为面试官问了我很多关于单例模式的问题,我回答的还可以,之后面试官随口问了一句"单例绝对安全吗?",紧接着发生了如下对话:

Q:单例模式绝对安全吗? 

A:(这个问题我知道,别想难倒我)不一定的,其实单例也是有可能被破坏的?

Q:哦?怎么说?

A:单例模式其实是对外隐藏了构造函数,保证用户无法主动创建对象。但是实际上我们是有办法可以破坏他的。

Q:那你知道有什么办法可以破坏单例吗??

A:有一个比较简单的方式,那就是反射

反射破坏单例

我们先来一个比较常见的单例模式:

import java.io.Serializable;    public class Singleton implements Serializable{      private volatile static Singleton singleton;      private Singleton (){}      public static Singleton getSingleton() {          if (singleton == null) {              synchronized (Singleton.class) {                  if (singleton == null) {                      singleton = new Singleton();                  }              }          }          return singleton;      }  }

这个单例模式提供了一个private类型的构造函数,正常情况下,我们无法直接调用对象的私有方法。但是反射技术给我们提供了一个后门。

如下代码,我们通过反射的方式获取到Singleton的构造函数,设置其访问权限,然后通过该方法创建一个新的对象:

import java.lang.reflect.Constructor;  public class SingletonTest {      public static void main(String[] args) {          Singleton singleton = Singleton.getSingleton();          try {              Class<Singleton> singleClass = (Class<Singleton>)Class.forName("com.dev.interview.Singleton");              Constructor<Singleton> constructor = singleClass.getDeclaredConstructor(null);              constructor.setAccessible(true);              Singleton singletonByReflect = constructor.newInstance();              System.out.println("singleton : " + singleton);              System.out.println("singletonByReflect : " + singletonByReflect);              System.out.println("singleton == singletonByReflect : " + (singleton == singletonByReflect));          } catch (Exception e) {              e.printStackTrace();          }      }  }

输出结果为:

singleton : com.dev.interview.Singleton@55d56113  singletonByReflect : com.dev.interview.Singleton@148080bb  singleton == singletonByReflect : false

如上,通过发射的方式即可获取到一个新的单例对象,这就破坏了单例。

Q:那这种破坏单例的情况,有办法避免吗?

A:其实是可以的,只要我们在构造函数中加一些判断就行了。

如下方式,我们在Singleton的构造函数中增加如下代码:

private Singleton() {      if (singleton != null) {          throw new RuntimeException("Singleton constructor is called... ");      }  }

这样,在通过反射调用构造方法的时候,就会抛出异常:

Caused by: java.lang.RuntimeException: Singleton constructor is called...

序列化破坏单例

Q:嗯嗯,挺不错的,那我们换个问题吧。

A:(这部分面试官在犹豫问我什么问题,我主动提醒了他一句)其实,除了反射可以破坏单例,还有一种其他方式也可以的。

Q:嗯,那你就说说还有什么方式吧 

A:其实通过序列化+反序列化的方式也是可以破坏单例的。

如以下代码,我们通过先将单例对象序列化后保存到临时文件中,然后再从临时文件中反序列化出来:

public class SingletonTest {      public static void main(String[] args) {          Singleton singleton = Singleton.getSingleton();          //Write Obj to file          ObjectOutputStream oos = null;          try {              oos = new ObjectOutputStream(new FileOutputStream("tempFile"));              oos.writeObject(singleton);              //Read Obj from file              File file = new File("tempFile");              ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));              Singleton singletonBySerialize = (Singleton)ois.readObject();              //判断是否是同一个对象             System.out.println("singleton : " + singleton);              System.out.println("singletonBySerialize : " + singletonBySerialize);              System.out.println("singleton == singletonBySerialize : " + (singleton == singletonBySerialize));          } catch (Exception e) {              e.printStackTrace();          }      }  }

输出结果如下:

singleton : com.dev.interview.Singleton@617faa95  singletonBySerialize : com.dev.interview.Singleton@5d76b067  singleton == singletonBySerialize : false

如上,通过先序列化再反序列化的方式,可获取到一个新的单例对象,这就破坏了单例。

因为在对象反序列化的过程中,序列化会通过反射调用无参数的构造方法创建一个新的对象,所以,通过反序列化也能破坏单例。

Q:那这种破坏单例的情况,也同样有办法避免吗?

A:当然也有了。只要修改下反序列化策略就好了。

只需要在Sinleton中增加readResolve方法,并在该方法中指定要返回的对象的生成策略几可以了。即序列化在Singleton类中增加以下代码即可:

private Object readResolve() {     return getSingleton();  }

Q:为什么增加readResolve就可以解决序列化破坏单例的问题了呢?

A:因为反序列化过程中,在反序列化执行过程中会执行到ObjectInputStream#readOrdinaryObject方法,这个方法会判断对象是否包含readResolve方法,如果包含的话会直接调用这个方法获得对象实例。

Java中怎么破坏单例方式

Q:那如果没有readResolve方法的话,反序列化的时候会怎么创建对象呢?

A:当然也是反射咯。

Q:那前面不是说使用反射的情况,直接在构造函数抛异常不就行了吗?

A:这个我还真试过,其实是不行的,反序列化使用的反射构造器和我们代码中使用反射的构造器不是同一个,反序列化用到的构造器并不会调用到我们对象中的构造函数&hellip;balabala&hellip;(我也不知道面试官听不听得懂,感觉是没听懂&hellip;)

Q:哦。OK吧,请问你什么时候可以来上班?

不久之后,我入职了这家公司,在一次和当初的面试官聊天的时候,他无意间和我说:当时我面试你的时候,关于单例的破坏那几个问题,其实最开始我只是随口一问,没想到你给我吹水了20分钟&hellip;当时我就觉得你这家伙是个可造之材。

“Java中怎么破坏单例方式”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: Java中怎么破坏单例方式

本文链接: https://lsjlt.com/news/283484.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java中怎么破坏单例方式
    本篇内容介绍了“Java中怎么破坏单例方式”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!单例模式(Singleton Pattern)是 J...
    99+
    2023-06-16
  • Java单例模式的创建,破坏和防破坏详解
    目录前言单例模式单例模式的几种实现方式懒汉式,线程不安全懒汉式,线程安全饿汉式双检锁/双重校验锁登记式/静态内部类枚举破坏单例模式未破坏的情况破坏后的情况单例模式的防破坏总结前言 ...
    99+
    2024-04-02
  • Java单例模式与破坏单例模式的概念是什么
    本文小编为大家详细介绍“Java单例模式与破坏单例模式的概念是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java单例模式与破坏单例模式的概念是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。什么是单例...
    99+
    2023-07-05
  • Java单例模式与破坏单例模式概念原理深入讲解
    目录什么是单例模式饿汉式(预加载)懒汉式(懒加载)反射破坏单例模式什么是单例模式 经典设计模式又分23种,也就是GoF 23 总体分为三大类: 创建型模式结构性模式行为型模式 Jav...
    99+
    2023-02-21
    Java单例模式 Java破坏单例模式
  • Java中单例模式怎么用
    这篇文章给大家分享的是有关Java中单例模式怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。注意单例类只能有一个实例。单例类必须自己创建自己的唯一实例。单例类必须给所有其他对象提供这一实例。优点在内存里只有一...
    99+
    2023-06-29
  • Java单例模式怎么写
    本篇内容主要讲解“Java单例模式怎么写”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java单例模式怎么写”吧!这个模式是很有意思,而且比较简单,但是我还是要说因为它使用的是如此的广泛,如此的...
    99+
    2023-06-19
  • Java单例模式怎么理解
    这篇文章主要讲解了“Java单例模式怎么理解”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java单例模式怎么理解”吧!一、设计模式概览1.1、软件设计模式的概念软件设计模式(Softwar...
    99+
    2023-06-22
  • java单例模式怎么实现
    Java中单例模式的实现方法有以下几种:1. 懒汉式(线程不安全):```public class Singleton {priva...
    99+
    2023-08-23
    java
  • java的单例模式怎么实现
    今天小编给大家分享一下java的单例模式怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下...
    99+
    2024-04-02
  • 怎么掌握Java的单例模式
    这篇“怎么掌握Java的单例模式”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么掌握Java的单例模式”文章吧。单例模式:...
    99+
    2023-06-30
  • java中单例模式与Singleton
    前言这一篇来源我的公众号,如果你没看过,正好直接看看,如果看过了也可以再看看,我稍微修改了一些内容,今天讲解的内容如下:一、什么是单例模式【单例模式】,英文名称:Singleton Pattern,这个模式很简单,一个类型只需要一个实例,他...
    99+
    2021-08-10
    java教程 单例模式 Singleton
  • java中单例模式讲解
    目录WHATWHYHOW饿汉式实现一:静态实例参数与静态代码块实现二:静态内部类懒汉式错误一:单线程实现错误二:同步方法错误三:同步代码块之单次检查错误四:同步代码块之双重检查正确:...
    99+
    2024-04-02
  • Java中输入输出方式的简单示例
    目录概述 一、输出到控制台(一)、基本语法(二)、代码示例(三)、格式化字符串二、从键盘输入1、使用 Scanner 读取字符串/整数/浮点数2、输入数据类型的方法3、注意事项:总结...
    99+
    2024-04-02
  • 详解Java中的八种单例创建方式
    目录定义使用场景单例模式八种方式饿汉式(静态常量)饿汉式(静态代码块)懒汉式(线程不安全)懒汉式(同步方法)懒汉式(同步代码块)双重检查锁方式静态内部类方式枚举方式总结 定义 单例设...
    99+
    2024-04-02
  • Java单例模式的五种实现方式
    目录前言饿汉单例懒汉单例非线程安全的懒汉单例加同步锁的懒汉单例双重检验懒汉单例静态内部类静态内部类为什么是线程安全总结前言 单例模式(Singleton Pattern)是 Java...
    99+
    2024-04-02
  • java怎么实现一个单例模式
    在Java中,可以通过以下两种方式来实现单例模式:1. 懒汉式单例模式(Lazy Initialization):```javapu...
    99+
    2023-09-27
    java
  • Java中的单例模式实例分析
    本篇内容介绍了“Java中的单例模式实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、定义单例模式(Singleton Patter...
    99+
    2023-06-29
  • Java单例创建方式有哪些
    本文小编为大家详细介绍“Java单例创建方式有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java单例创建方式有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。定义单例设计模式,就是采取一定的方法保证在...
    99+
    2023-06-29
  • 分析Java中的单例模式
    本篇内容主要讲解“分析Java中的单例模式”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“分析Java中的单例模式”吧!WHAT维基百科给出了解释、实现的思路以及应该注意的地方:单例模式,也叫单子...
    99+
    2023-06-25
  • 怎么在java中实现一个饱汉模式单例
    这篇文章将为大家详细讲解有关怎么在java中实现一个饱汉模式单例,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序、Web应用程...
    99+
    2023-06-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作