Java中实现单例模式的方式
1. 使用静态内部类实现单例模式
在Java中,使用静态内部类实现单例模式是一种常见而又有效的方式。这种方式被称为“静态内部类单例模式”或者“Holder模式”。这种实现方式有以下优点:
-
懒加载(Lazy Initialization):静态内部类不会在外部类加载的时候就被加载,而是在第一次被调用的时候才会加载。这就实现了懒加载,即在需要的时候才创建单例对象,避免了在应用启动时就创建对象的开销。
-
线程安全(Thread-Safe):由于静态内部类只会被加载一次,因此在加载过程中,其他线程无法访问静态内部类的加载过程。这就天然地保证了线程安全性。
public class Singleton {// 私有化构造函数,防止外部直接实例化private Singleton() {}// 静态内部类,用于持有单例对象private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}// 获取单例对象的方法public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
}
2. 使用序列化和反序列化实现单例模式
在Java中,使用标准的序列化和反序列化机制时,可能会破坏单例模式,因为反序列化会创建一个新的对象。为了避免这个问题,可以在单例类中添加一个特殊的方法,以便在反序列化时返回现有的单例对象。
import java.io.*;public class Singleton implements Serializable {private static final long serialVersionUID = 1L;// 私有化构造函数,防止外部直接实例化private Singleton() {}// 单例实例private static final Singleton INSTANCE = new Singleton();// 获取单例对象的方法public static Singleton getInstance() {return INSTANCE;}// 在反序列化时,确保返回相同的单例对象protected Object readResolve() throws ObjectStreamException {return INSTANCE;}public static void main(String[] args) {// 序列化try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton.ser"))) {oos.writeObject(Singleton.getInstance());} catch (IOException e) {e.printStackTrace();}// 反序列化try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("singleton.ser"))) {Singleton deserializedInstance = (Singleton) ois.readObject();System.out.println("Original Singleton HashCode: " + Singleton.getInstance().hashCode());System.out.println("Deserialized Singleton HashCode: " + deserializedInstance.hashCode());} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}
readResolve() 是一个特殊的回调方法,用于在反序列化时返回实际要返回的对象。这个方法允许开发者指定在反序列化过程中应该返回哪个对象。
3. 使用静态代码块实现单例模式
使用静态代码块实现单例模式是一种常见的方式。通过在静态代码块中进行对象的实例化,可以保证在类加载的时候只执行一次,从而实现单例模式。
public class Singleton {// 私有化构造函数,防止外部直接实例化private Singleton() {}// 单例实例private static final Singleton INSTANCE;// 静态代码块,在类加载时执行,用于初始化单例实例static {try {INSTANCE = new Singleton();} catch (Exception e) {throw new RuntimeException("Error creating singleton instance");}}// 获取单例对象的方法public static Singleton getInstance() {return INSTANCE;}public static void main(String[] args) {// 获取单例对象Singleton singleton = Singleton.getInstance();}
}
4. 使用枚举实现单例模式
在Java中,使用枚举(enum)实现单例模式是一种简洁且线程安全的方式。枚举本身就天然地具有单例的特性,保证在任何情况下都只有一个实例。这是因为Java中的枚举类型是线程安全且只能被实例化一次的。
- JVM保证枚举的线程安全性: Java中的枚举类型在JVM层面被设计为线程安全的,这是因为枚举实例在类加载的时候就被创建,且JVM会保证每个枚举值只被实例化一次。
- 保证实例的唯一性: 枚举类型的实例是在枚举类加载时被创建的,而且在整个应用程序的生命周期中,它们只会被创建一次。这就保证了枚举实例的唯一性,因此枚举天生就符合单例模式的要求。
- 简洁且防御反射攻击: 使用枚举实现单例模式的代码非常简洁,而且防御了一些反射攻击,因为枚举的实例在类加载的时候就被创建,不会受到反射的影响。
public enum Singleton {INSTANCE; // 单例实例// 可以在枚举中添加其他方法public void someMethod() {// 实现方法逻辑}public static void main(String[] args) {// 获取单例对象Singleton singleton = Singleton.INSTANCE;// 调用其他方法singleton.someMethod();}
}相关文章:
Java中实现单例模式的方式
1. 使用静态内部类实现单例模式 在Java中,使用静态内部类实现单例模式是一种常见而又有效的方式。这种方式被称为“静态内部类单例模式”或者“Holder模式”。这种实现方式有以下优点: 懒加载(Lazy Initialization):静…...
Vue3-01-创建项目
环境准备 1.需要用到 16.0 以及更高版本的 node.js 2.使用vscode编辑器进行项目开发可以在命令行中查看node的版本号: node -v创建项目 1.准备一个目录 例如,我创建项目的时候是在该目录下进行的;D:\projectsTest\vue3project2.执行创建命令(*&#x…...
Go 语言中的反射机制
欢迎大家到我的博客浏览,更好的阅读体验请点击 反射 | YinKais Blog 反射在大多数的应用和服务中并不常见,但是很多框架都依赖 Go 语言的反射机制简化代码。<!--more-->因为 Go 语言的语法元素很少、设计简单,所以它没有特别强的表达能…...
[leetcode 前缀和]
525. 连续数组 M :::details 给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。 示例 1: 输入: nums [0,1] 输出: 2 说明: [0, 1] 是具有相同数量 0 和 1 的最长连续子数组。示例 2: 输入: nums [0,1,0] 输出: …...
Python与ArcGIS系列(十五)根据距离抓取字段
目录 0 简述1 实例需求2 arcpy开发脚本0 简述 在处理gis数据的时候,会遇到这种需求:将一个图层与另一个图层中相近的要素进行字段赋值。本篇将介绍如何利用arcpy及arcgis的工具箱实现这个功能。 1 实例需求 为了介绍这个功能的实现,我们需要有一个特定的功能需求。在这里选…...
YOLOv8分割训练及分割半自动标注
YOLOv8是基于目标检测算法YOLOv5的改进版,它在YOLOv5的基础上进行了优化和改进,加入了一些新的特性和技术,如切片注意力机制、骨干网络的选择等。 本文以yolov8-seg为基准,主要整理分割训练流程及使用v8分割模型进行半自动标注的过程。 一、v8-seg训练 1.1 环境配置 github…...
jsp页面通过class或者id获取a标签上的属性的值
要通过class和id两种方式获取a标签上的某个属性的值,或者给其赋值,可以使用JavaScript。以下是两种方法的示例: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name&q…...
题目:美丽的区间(蓝桥OJ 1372)
题目描述: 解题思路: 采用双指针的快慢指针。 图解 可以采用前缀和,但会相较麻烦。 题解: #include<bits/stdc.h> using namespace std;const int N 1e5 9; int a[N];// 因为是连续区间(连续区间࿱…...
解决:During handling of the above exception, another exception occurred
解决:During handling of the above exception, another exception occurred 文章目录 解决:During handling of the above exception, another exception occurred背景报错问题报错翻译报错位置代码报错原因解决方法参考内容:今天的分享就到…...
计算机基础知识65
cookie和session的使用 # 概念:cookie 是客户端浏览器上的键值对 # 目的:为了做会话保持 # 来源:服务端写入的,服务端再返回的响应头中写入,浏览器会自动取出来 存起来是以key value 形式,有过期时间、path…...
Python开发运维:Python垃圾回收机制
目录 一、理论 1.Python垃圾回收机制 一、理论 1.Python垃圾回收机制 (1)引⽤计数器 1)环状双向链表 refchain 在python程序中创建的任何对象都会放在refchain链表中。 name "david" age 20 hobby ["篮球",游泳…...
ros2/ros安装ros-dep||rosdep init错误
第一个错误的做法: sudo apt-get install python3-pip sudo pip3 install 6-rosdep sudo 6-rosdep 如果使用上述代码将会摧毁整个系统,不重装系统反正我是搞不定啊,因为我不知道那个写软件的人到底做了什么。因为这个我安装的版本是humble&…...
《深入理解计算机系统》学习笔记 - 第四课 - 机器级别的程序
Lecture 05 Machine Level Programming I Basics 机器级别的程序 文章目录 Lecture 05 Machine Level Programming I Basics 机器级别的程序intel 处理器的历史和体系结构芯片的构成AMD 公司(Advanced Micro Devices,先进的微型设备) C, 汇编, 机器代码定义汇编/机器…...
云原生(Cloud Native)——概念,技术,背景,优缺点,实践例子
云原生(Cloud Native)是一种构建和运行应用程序的方法,这些应用程序充分利用云计算的优势。云原生应用程序通常设计为在现代、动态的环境中运行,如公共云、私有云和混合云。这种方法强调微服务架构、容器化、自动化、易于管理和可…...
ElasticSearch之线程池
ElasticSearch节点可用的CPU核的数量,通常可以交给ElasticSearch来自行检测和判定,另外可以在elasticsearch.yml中显式指定。样例如下: node.processors: 2如下表格中的processors即CPU核的数量。 线程池的列表 线程池名称类型线程数量队列…...
StoneDB-8.0-V2.2.0 企业版正式发布!性能优化,稳定性提升,持续公测中!
11月,StoneDB 新版本如期而至,这一个月来我们的研发同学加班加点,持续迭代:在 2.2.0 版本中,我们针对用户提出的需求和做出了重量级更新,修复了一些已知和用户反馈的 Bug,同时对部分代码进行…...
【数据结构 — 排序 — 插入排序】
数据结构 — 排序 — 插入排序 一.排序1.1.排序的概念及其运用1.1.1排序的概念1.1.2排序运用1.1.3 常见的排序算法 二.插入排序2.1.直接插入排序2.1.1.算法讲解2.1.2.代码实现2.1.2.1.函数定义2.1.2.2.算法接口实现2.1.2.3.测试代码实现2.1.2.4.测试展示 2.2.希尔排序2.2.1.算法…...
物联网后端个人第十四周总结
物联网方面进度 1.登陆超时是因为后端运行的端口和前端监听的接口不一样,所以后端也没有报错,将二者修改一致即可 2.登录之后会进行平台的初始化,但是初始化的时候会卡住,此时只需要将路径的IP端口后边的内容去掉即可 3.阅读并完成了jetlinks…...
在uniapp中,可以使用那些预定义的样式类
u-flex:设置元素为弹性布局。u-flex-v:设置元素为纵向弹性布局。u-flex-h:设置元素为横向弹性布局。u-p-10:设置元素的上下左右边距为10rpx。u-p-t-10:设置元素的上边距为10rpx。u-p-b-10:设置元素的下边距…...
mybatis的数据库连接池
直接看原文 原文链接:【MyBatis】 连接池技术_mybatis自带连接池-CSDN博客 本文先不说springBoot整合mybatis后的 本文讲的是没有被springBoot整合前的mybatis自己的默认的连接池 --------------------------------------------------------------------------------------…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
uni-app学习笔记三十五--扩展组件的安装和使用
由于内置组件不能满足日常开发需要,uniapp官方也提供了众多的扩展组件供我们使用。由于不是内置组件,需要安装才能使用。 一、安装扩展插件 安装方法: 1.访问uniapp官方文档组件部分:组件使用的入门教程 | uni-app官网 点击左侧…...
Python常用模块:time、os、shutil与flask初探
一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...
链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...
