Elvis java_Java中Singleton的3种实现方式详解

2023-11-03 23:20

本文主要是介绍Elvis java_Java中Singleton的3种实现方式详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

776e71d35e8b5eb8b9f04cbf6ea57573.png

一、什么是Singleton?

《设计模式》的作者、Eclipse和 Junit 的开发者 Erich Gamma 在它的理论体系中将 Singleton 定义为仅仅被实例化一次的类。在当今面向对象程序的实际开发中,Singleton 通常被用来代表一个无状态的对象,例如函数和那些本质上唯一的系统组件。

值得注意的是,使类成为 Singleton 会使得它的客户端测试变得非常困难,因为我们不可能给Singleton替换模拟实现,除非我们实现一个充当其类型的接口。

实现 Singleton 有三种常见方法,他们或是保持构造器私有并导出公有的静态成员,或是声明一个包含单个元素的枚举类型。

二、Singleton实现 ―― 构造器私有

1、公有静态成员为一个final域

//Singleton with public final field

public class Elvis {

public static final Elvis INSTANCE = new Elvis();

pritvate Elvis() { ... }

public void leaveTheBuilding() { ... }

}

在这个类中,我们仅仅拥有一个私有的构造器,它也只在初始化final域时被调用一次。由于缺少可以使用的构造器,后续的程序无法再创建 Elvis 对象。这保证了在该Java程序的整个生命周期中, Elvis 对象有且只有一个存在。

但需要注意的是,一些高权限的客户端可以借助 AccessibleObject.setAccessible 方法通过反射机制调用私有的构造器。为了避免这样的可能的攻击,可以修改构造器,让它在被要求创建第二个实例的时候抛出异常。

公有域方法的主要优势在于,API很清楚地表明了这个类是一个 Singleton ,毕竟这是一个公有的静态属性。另外,这个方法要更加简单。

2、公有静态成员为一个静态工厂方法

//Singleton with static factory

public class Elvis {

private static final Elvis INSTANCE = new Elvis();

pritvate Elvis() { ... }

public static Elvis getInstance(){ return INSTANCE; }

public void leaveTheBuilding(){ ... }

}

显然,无论怎样调用 getInstance 方法,返回的都是同一个对象的引用。注意上面提示的反射攻击问题依然存在。

静态工厂方法有三大优势

第一,它提供了更多的灵活性,在不改变API的前提下,我们可以轻易地自由调整这个类是否是Singleton。工厂方法返回该类的唯一实例,但它很容易修改成别的样子,例如为每个调用该方法的线程提供唯一实例。

第二,如果程序需要,我们可以编写一个泛型 Singleton 工厂。

第三,我们可以通过方法引用作为提供者,比如 Elvis::instance 就是一个 Supplier< Elvis >

(注:方法引用是Java8的一个新特性)

除非我们需要上述的其中一种优势,我们还是应该选择更简单易懂的使用公有域的方法。

3、将利用上述方法实现的Singleton类变为可序列化的

使用上述两种方法实现的 Singleton ,要把他们变成可序列化的,不能仅仅在声明中加上 implements Serializable 。为了维护并保证 Singleton ,我们必须生命所有实例域都是瞬时的,并提供一个 readResolve 方法。否则在我们每次序列化时都会创建一个新的实例。为了防止这种情况,我们要在 Elvis 类中加入如下这样的 readResolve 方法。

//readResolve method to preserve singleton property

private Object readResolve(){

//Return the one true Elvis and let the garbage collector take care of the Elvis impersonator

return INSTANCE;

}

三、Singleton实现 ―― 声明包含单个元素的枚举类型

//Enum singleton - the preferred approach

public enum Elvis{

INSTANCE;

public void leaveTheBuilding(){ ... }

}

这种方法在功能上与公有域方法相似,但更加简洁,无偿地提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击的时候。 虽然这种方法还没有广泛采用,但是单元素的枚举类型经常成为实现 Singleton 的最佳方法。 注意,如果 Singleton 必须扩展一个超类,而不是扩展 Enum 的时候,则不宜使用这个方法(虽然可以声明枚举去实现接口)。

总结

到此这篇关于Java中Singleton的3种实现方式的文章就介绍到这了,更多相关Java Singleton实现方式内容请搜索云海天教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持云海天教程!

这篇关于Elvis java_Java中Singleton的3种实现方式详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/341572

相关文章

Conda与Python venv虚拟环境的区别与使用方法详解

《Conda与Pythonvenv虚拟环境的区别与使用方法详解》随着Python社区的成长,虚拟环境的概念和技术也在不断发展,:本文主要介绍Conda与Pythonvenv虚拟环境的区别与使用... 目录前言一、Conda 与 python venv 的核心区别1. Conda 的特点2. Python v

Spring Boot中WebSocket常用使用方法详解

《SpringBoot中WebSocket常用使用方法详解》本文从WebSocket的基础概念出发,详细介绍了SpringBoot集成WebSocket的步骤,并重点讲解了常用的使用方法,包括简单消... 目录一、WebSocket基础概念1.1 什么是WebSocket1.2 WebSocket与HTTP

SpringBoot+Docker+Graylog 如何让错误自动报警

《SpringBoot+Docker+Graylog如何让错误自动报警》SpringBoot默认使用SLF4J与Logback,支持多日志级别和配置方式,可输出到控制台、文件及远程服务器,集成ELK... 目录01 Spring Boot 默认日志框架解析02 Spring Boot 日志级别详解03 Sp

Python使用python-can实现合并BLF文件

《Python使用python-can实现合并BLF文件》python-can库是Python生态中专注于CAN总线通信与数据处理的强大工具,本文将使用python-can为BLF文件合并提供高效灵活... 目录一、python-can 库:CAN 数据处理的利器二、BLF 文件合并核心代码解析1. 基础合

java中反射Reflection的4个作用详解

《java中反射Reflection的4个作用详解》反射Reflection是Java等编程语言中的一个重要特性,它允许程序在运行时进行自我检查和对内部成员(如字段、方法、类等)的操作,本文将详细介绍... 目录作用1、在运行时判断任意一个对象所属的类作用2、在运行时构造任意一个类的对象作用3、在运行时判断

Python使用OpenCV实现获取视频时长的小工具

《Python使用OpenCV实现获取视频时长的小工具》在处理视频数据时,获取视频的时长是一项常见且基础的需求,本文将详细介绍如何使用Python和OpenCV获取视频时长,并对每一行代码进行深入解析... 目录一、代码实现二、代码解析1. 导入 OpenCV 库2. 定义获取视频时长的函数3. 打开视频文

golang版本升级如何实现

《golang版本升级如何实现》:本文主要介绍golang版本升级如何实现问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录golanwww.chinasem.cng版本升级linux上golang版本升级删除golang旧版本安装golang最新版本总结gola

java如何解压zip压缩包

《java如何解压zip压缩包》:本文主要介绍java如何解压zip压缩包问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java解压zip压缩包实例代码结果如下总结java解压zip压缩包坐在旁边的小伙伴问我怎么用 java 将服务器上的压缩文件解压出来,

MySQL 中的 CAST 函数详解及常见用法

《MySQL中的CAST函数详解及常见用法》CAST函数是MySQL中用于数据类型转换的重要函数,它允许你将一个值从一种数据类型转换为另一种数据类型,本文给大家介绍MySQL中的CAST... 目录mysql 中的 CAST 函数详解一、基本语法二、支持的数据类型三、常见用法示例1. 字符串转数字2. 数字

SpringBoot中SM2公钥加密、私钥解密的实现示例详解

《SpringBoot中SM2公钥加密、私钥解密的实现示例详解》本文介绍了如何在SpringBoot项目中实现SM2公钥加密和私钥解密的功能,通过使用Hutool库和BouncyCastle依赖,简化... 目录一、前言1、加密信息(示例)2、加密结果(示例)二、实现代码1、yml文件配置2、创建SM2工具