Java之枚举

目录
枚举
引入
定义
代码示例
常用方法
代码示例
枚举的优缺点
枚举和反射
面试题
枚举
引入
枚举是在JDK1.5以后引入的。主要用途是:将一组常量组织起来,在这之前表示一组常量通常使用定义常量的方式:
publicstaticintfinalRED=1;
publicstaticintfinalGREEN=2;publicstaticintfinalBLACK=3;
但是常量举例有不好的地方,例如:可能碰巧有个数字1,但是他有可能误会为是RED,现在我们可以直接用枚举来进行组织,这样一来,就拥有了类型,枚举类型。而不是普通的整形1。
定义
在Java中,枚举类型是通过关键字enum来定义的。
枚举的定义类似于类的定义,但它使用enum关键字而不是class关键字。枚举可以包含字段、方法和构造函数,但构造函数默认是私有的,以防止外部代码创建枚举的实例。
本质:是 java.lang.Enum的子类,也就是说,自己写的枚举类,就算没有显示继承 Enum,但是它默认继承了这个类。
publicenumTestEnum{RED,BLACK,GREEN;
}
代码示例
public enum TestEnum {//枚举对象RED,WHITE,GREEN;public static void main(String[] args) {TestEnum testEnum = TestEnum.RED;switch (testEnum) {case RED:System.out.println("红色");break;case GREEN:System.out.println("绿色");break;case WHITE:System.out.println("白色");break;default:break;}}}
运行结果:

常用方法
| 方法名称 | 描述 |
| values() | 以数组形式返回枚举类型的所有成员 |
| ordinal() | 获取枚举成员的索引位置 |
| valueOf() | 将普通字符串转换为枚举类型 |
| compareTo() | 比较两个枚举类型成员在定义时的顺序 |
当枚举对象有参数后,需要提供相应的构造函数,枚举的构造函数默认是私有的。
代码示例
public enum TestEnum {
// 枚举对象RED(1,"RED"),WHITE(2,"WHITE"),GREEN(3,"GREEN");public String color;public int ordinal;private TestEnum(int ordinal,String color) {this.ordinal = ordinal;this.color = color;}public static void main(String[] args) {TestEnum[] testEnums = TestEnum.values();for (int i = 0; i < testEnums.length; i++) {System.out.println(testEnums[i]+" "+testEnums[i].ordinal());}System.out.println("=====");TestEnum testEnum = TestEnum.valueOf("RED");System.out.println(testEnum);System.out.println(RED.compareTo(WHITE));}
}
运行结果:

枚举的优缺点
优点
1.类型安全:枚举类型是编译时常量,它们比使用整数值或字符串常量更加安全。
2.自动封装:枚举类型提供了编译时的类型检查,确保了只有声明在枚举中的值才能被赋值给枚举类型的变量。
3.可以包含字段和方法:枚举类型可以拥有字段、方法和构造函数。
4.构造器限制:枚举的构造函数默认是私有的,防止外部代码实例化枚举。
5.实现接口:枚举类型可以实现一个或多个接口。
缺点:
1.不可变性限制:Java中的枚举实例默认是不可变的(即枚举值一旦创建,其状态就不能改变)。这种不可变性在大多数情况下是一个优点,因为它有助于保证线程安全和简化代码逻辑。然而,在某些情况下,你可能希望枚举值能够改变其状态,但这在Java枚举中是不被允许的。虽然你可以通过枚举中的方法改变枚举关联的其他对象的状态,但这通常不是最佳实践。
2.继承限制:Java中的枚举类型隐式地继承自java.lang.Enum类,并且Java不支持多重继承。因此,枚举类型不能继承自除java.lang.Enum之外的任何其他类。这限制了枚举的灵活性,并可能导致一些设计上的折衷。
枚举和反射
枚举是否能通过反射拿到实例对象呢?
代码示例
public enum TestEnum {
// 枚举对象RED(1,"RED"),WHITE(2,"WHITE"),GREEN(3,"GREEN");public String color;public int ordinal;private TestEnum(int ordinal,String color) {this.ordinal = ordinal;this.color = color;}public static void main(String[] args) throws ClassNotFoundException {Class<?> c = Class.forName("enumDemo.TestEnum");try {Constructor<?> constructor= c.getDeclaredConstructor(int.class,String.class);constructor.setAccessible(true);TestEnum testEnum= (TestEnum)constructor.newInstance(99,"hello");System.out.println(testEnum);} catch (NoSuchMethodException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}}
}
运行结果:

我们注意到,异常信息是:java.lang.NoSuchMethodException: enumDemo.TestEnum.<init>(int, java.lang.String)。
这是什么意思呢?就是没有对应的构造方法,但是我们明明已经提供了枚举的构造方法且两个参数分别是 int 和 String,那么问题出在哪里呢?
前面我们提到,所有的枚举类都默认继承于 java.lang.Enum,继承了父类除构造函数之外的所有内容,并且子类要帮助父类进行构造,而我们写的类并没有帮助父类构造,那是否意味着,我们要在实现的枚举类中提供 super 呢?
并不是,枚举类比较特殊,虽然我们实现的构造函数是两个参数,但是它默认还添加了两个参数,那添加的两个参数是什么呢?下面我们看一下Enum类的部分源码:

也就是说,我们自己的构造函数有两个参数一个是int一个是String,同时他默认在此前面还会给两个参数,一个是String一个是int。也就是说,这里我们正确给的是4个参数,修改后的代码:
public static void main(String[] args) throws ClassNotFoundException {Class<?> c = Class.forName("enumDemo.TestEnum");try {Constructor<?> constructor= c.getDeclaredConstructor(String.class,int.class,int.class,String.class);constructor.setAccessible(true);TestEnum testEnum= (TestEnum)constructor.newInstance("ceshi",999,99,"hello");System.out.println(testEnum);} catch (NoSuchMethodException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}
}
运行结果:

为什么此时在newInstance()方法会抛出异常: java.lang.IllegalArgumentException: Cannot reflectively create enum objects。
下面我们看看 newInstance() 方法的源码:

解释:
在这段代码中,if ((clazz.getModifiers() & Modifier.ENUM) != 0) 这一行是用来检查给定的类(clazz)是否是一个枚举(Enum)类型。
这里使用了位运算和位掩码的概念来检查类的修饰符中是否包含了枚举(Enum)的修饰符。在Java中,每个类都可以有一组修饰符,这些修饰符定义了类的性质,比如是否是公开的(public)、私有的(private)、受保护的(protected)、抽象的(abstract)、最终的(final)等,以及是否是枚举(enum)。这些修饰符在内部是通过整数(通常是int类型)的位模式来表示的,每个修饰符都对应一个特定的位位置。
Modifier.ENUM 是一个在 java.lang.reflect.Modifier 类中定义的常量,它代表了枚举类型的位掩码。这个常量是一个整数,其位模式中的某一位(或几位,但在这个上下文中通常只是一位)被设置为1,以表示枚举类型。
clazz.getModifiers() 方法返回了一个整数,这个整数包含了clazz类的所有修饰符的位模式。
& 是按位与(AND)运算符,它对两个整数进行操作,并返回一个新的整数,这个整数的每一位都是原来两个整数对应位进行AND操作的结果。如果两个整数在某一位上都是1,则结果在该位上也是1;否则,结果在该位上是0。
因此,clazz.getModifiers() & Modifier.ENUM 的结果是一个整数,它只在clazz的修饰符中包含枚举类型修饰符时才不为0。如果结果不为0,说明clazz是一个枚举类型;如果结果为0,说明clazz不是一个枚举类型。
所以,if ((clazz.getModifiers() & Modifier.ENUM) != 0) 这行代码的意思是:“如果clazz是一个枚举类型,则执行接下来的代码块(在这个例子中,是抛出一个IllegalArgumentException异常)”。这是因为在Java中,你不能通过反射来实例化枚举类型的对象,因为枚举的实例通常是通过枚举类型本身定义的常量来访问的,而不是通过构造函数创建的。
面试题
为什么枚举实现单例是线程安全的?
1.自动线程安全:Java的枚举类型是自动支持线程安全的。因为枚举类型本质上是通过类的静态字段来实现的,并且JVM保证了每个枚举实例在JVM中是唯一的。这意味着,在并发环境下,枚举实例的创建和访问都是线程安全的,无需额外的同步措施。
2.防止反射攻击:Java的枚举还有一个重要的特性,那就是它们默认是final的,并且枚举的构造函数默认也是私有的。这意味着枚举的实例不能被继承,也不能通过反射来调用枚举的构造函数来创建新的实例(尽管技术上可以通过反射调用私有构造函数,但Java平台禁止通过反射实例化枚举,如果尝试这样做,会抛出IllegalArgumentException或IllegalAccessException异常)。这种限制确保了枚举实例的唯一性和不可变性,从而增强了单例模式的安全性。
3.自动序列化机制:枚举类型还提供了自动的序列化机制。当枚举实例被序列化时,Java序列化机制仅仅是将枚举的name属性(即枚举常量的名称)输出到序列化流中,而不是像普通对象那样序列化其状态。反序列化时,Java通过枚举的name来查找枚举类型中对应的枚举常量,从而恢复枚举实例。这个机制确保了枚举实例在序列化和反序列化过程中仍然保持单例。
4.简单性和易用性:使用枚举实现单例模式非常简单,只需要定义一个枚举类型,并在其中定义一个枚举常量即可。这种实现方式既简洁又直观,易于理解和维护。
综上所述,枚举实现单例模式之所以被认为是安全的,主要是因为它提供了自动的线程安全、防止了反射攻击、支持自动序列化机制,并且实现简单、易用。这些特性使得枚举成为实现单例模式的理想选择之一。
相关文章:
Java之枚举
目录 枚举 引入 定义 代码示例 常用方法 代码示例 枚举的优缺点 枚举和反射 面试题 枚举 引入 枚举是在JDK1.5以后引入的。主要用途是:将一组常量组织起来,在这之前表示一组常量通常使用定义常量的方式: publicstaticintfinalRED1;…...
八、适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口之间进行合作。适配器模式通过创建一个适配器类来转换一个接口的接口,使得原本由于接口不兼容无法一起工作的类可以一起工作。 主要组成部分: 目标…...
关于E-R图
一 什么是E-R图 E-R图(Entity-Relationship Diagram)是一种数据建模工具,用于描述数据库中实体之间的关系。它使用实体(Entity)、属性(Attribute)和关系(Relationship&#…...
DVWA通关教程
Brute Force Low 先进行一下代码审计 <?php // 检查是否通过GET请求传递了Login参数(注意:这里应该是username或类似的,但代码逻辑有误) if( isset( $_GET[ Login ] ) ) { // 从GET请求中获取用户名 $user $_GET[ us…...
网络学习-eNSP配置VRRP
虚拟路由冗余协议(Virtual Router Redundancy Protocol,简称VRRP) VRRP广泛应用在边缘网络中,是一种路由冗余协议,它的设计目标是支持特定情况下IP数据流量失败转移不会引起混乱,允许主机使用单路由器,以及即使在实际…...
Kafka【九】如何实现数据的幂等性操作
为了解决Kafka传输数据时,所产生的数据重复和乱序问题,Kafka引入了幂等性操作,所谓的幂等性,就是Producer同样的一条数据,无论向Kafka发送多少次,kafka都只会存储一条。注意,这里的同样的一条数…...
JavaScript知识点1
目录 1.JavaScript中常用的数组方法有哪些? 2.JavaScript的同源策略? 3.JavaScript中的 NaN 是什么? 4.JavaScript中的split、slice、splice函数区别? 1.JavaScript中常用的数组方法有哪些? 在 JavaScript 中&…...
51单片机个人学习笔记11(AT24C02-I2C总线)
前言 本篇文章属于STC89C52单片机(以下简称单片机)的学习笔记,来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记,只能做参考,细节方面建议观看视频,肯定受益匪浅。 [1-1] 课程简介_哔哩…...
创建Java项目,可实现main方法运行,实现对性能数据的处理
1、Android Studio无法执行Java类的main方法问题及解决方法 Android Studio无法执行Java类的main方法问题及解决方法_delegatedbuild-CSDN博客 D:\workspaces\performanceTools\.idea 文件夹下,gardle.xml ,添加依赖 <option name"delegatedBuild"…...
JavaWeb(后端)
MVC MVC 就是 Model View Controller 的缩写,属于一种软件架构设计模式一种思想,把我们的项目分为控制器(Controller)、模型(Model)、视图(view)三个部分,model就是处理…...
828华为云征文 | 华为云Flexusx实例,高效部署Servas书签管理工具的优选平台
前言 华为云Flexus X实例,Servas书签管理工具部署的优选平台!828节日特惠,让高效管理您的知识宝藏触手可及。Flexus X实例以其卓越的算力、灵活的资源配置和智能调优技术,为Servas提供了稳定、高效的运行环境。无论是快速访问、安…...
分治法和动态规划法
一、分治法(Divide and Conquer) 定义 分治法是一种将大问题分解成若干个小问题,递归地解决这些小问题,然后将这些小问题的解合并起来得到原问题的解的算法策略。(子问题之间相互独立) 基本步骤 1.分解…...
【FreeRL】我的深度学习库构建思想
文章目录 前言参考python环境效果已复现结果 综述DQN.py(主要)算法实现参数修改细节实现显示训练,保存训练 Buffer.pyevaluate.pylearning_curves 前言 代码实现在:https://github.com/wild-firefox/FreeRL 欢迎star 参考 动手学强化学习e…...
Docker部署nginx容器无法访问80端口
问题说明 在阿里云ECS服务器上部署一台CentOS服务器,然后在里面安装了docker服务。用docker部署了nginx,开启docker中的nginx服务,映射宿主机端口80 把阿里云服务器上面的安全组放开了80端口 但是还是无法访问nginx的80web界面 问题分析 查…...
Python语言开发学习之使用Python预测天气
什么是wttr? 使用Python预测天气的第一步,我们要了解wttr是什么。wttr.in是一个面向控制台的天气预报服务,它支持各种信息表示方法,如面向终端的ANSI序列(用于控制台HTTP客户端(curl、httpie或wget))、HTML(用于web浏览器)或PNG(…...
minio实现大文件断点续传
最近工作中遇到一个需求,用户需要上传大文件几百M,为了更好的用户体验,需要支持断点续传,秒传,上传进度条等功能。需求如下: 方案有两种: 第一种:前端直接将整个大文件丢到后端&…...
Qt绘制动态仪表(模仿汽车仪表指针、故障灯)
背景: 项目需要,可能需要做一些仪表显示。此篇除了介绍实现方法,还要说明心路历程。对我而言,重要的是心理,而不是技术。写下来也是自勉。 本人起初心里是比较抵触的,从业20多年了,深知所谓界…...
【视频教程】GEE遥感云大数据在林业中的应用与典型案例实践
近年来遥感技术得到了突飞猛进的发展,航天、航空、临近空间等多遥感平台不断增加,数据的空间、时间、光谱分辨率不断提高,数据量猛增,遥感数据已经越来越具有大数据特征。遥感大数据的出现为相关研究提供了前所未有的机遇…...
【时时三省】c语言例题----华为机试题<字符串排序>
山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 1,题目 HJ14 字符串排序 描述 给定 n 个字符串,请对 n 个字符串按照字典序排列。 数据范围: 1≤n≤1000 1≤n≤1000 ,字符串长度满足 1≤l…...
基于vue框架的城市体育运动交流平台15s43(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
系统程序文件列表 项目功能:用户,赛事类型,近期赛事,比赛报名,器材类型,器材信息,自由约战,运动队伍 开题报告内容 基于Vue框架的城市体育运动交流平台开题报告 一、项目背景与意义 随着城市化进程的加速和居民健康意识的提升,城市体育运动已成为现代…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁
赛门铁克威胁猎手团队最新报告披露,数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据,严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能,但SEMR…...
【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解
一、前言 在HarmonyOS 5的应用开发模型中,featureAbility是旧版FA模型(Feature Ability)的用法,Stage模型已采用全新的应用架构,推荐使用组件化的上下文获取方式,而非依赖featureAbility。 FA大概是API7之…...
CSS3相关知识点
CSS3相关知识点 CSS3私有前缀私有前缀私有前缀存在的意义常见浏览器的私有前缀 CSS3基本语法CSS3 新增长度单位CSS3 新增颜色设置方式CSS3 新增选择器CSS3 新增盒模型相关属性box-sizing 怪异盒模型resize调整盒子大小box-shadow 盒子阴影opacity 不透明度 CSS3 新增背景属性ba…...
