Java 枚举

目录

枚举是什么

常用方法

构造方法

枚举的优缺点

枚举和反射

实现单例模式


枚举是什么

枚举(enum):是一种特殊的类,用于定义一组常量,将其组织起来。枚举使得代码更具有可读性和可维护性,特别是在处理固定集合的值时,如:星期、月份、状态码等

在 Java 中,使用关键字 enum 来定义枚举类:

public enum Day {SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;
}

其中,定义的枚举项就是该类的实例,且必须在第一行,最后一个枚举项后的分号; 可以省略,但是若枚举类有其他内容,则分号不能省略(最好不要省略) 

当类初始化时,这些枚举项就会被实例化

枚举类使用 enum 定义后,默认继承 java.lang.Enum 类,也就是说,我们自己写的枚举类,就算没有显示的继承 Enum,但是其默认继承了这个类

此外,枚举在 Java 中不能被继承,自定义的枚举类隐式继承自 java.lang.Enum 类,且不能再继承其他类,这样的设计确保了枚举类的简单性和一致性。如果枚举可以继承其他类,将会导致复杂的继承关系,并且影响Java的类型系统

常用方法

方法描述
values()以数组的形式返回枚举类型的所有成员

ordinal()

获取枚举成员的索引位置
valueOf()将普通字符串转换为枚举实例

compareTo(E o)

比较两个枚举成员在定义时的顺序

 我们通过一个示例,来学习和使用这些方法:

public enum Day {SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;public static void main(String[] args) {// 获取所有枚举成员Day[] days = Day.values();// 遍历for (int i = 0; i < days.length; i++) {// 获取枚举成员以及索引位置System.out.println(days[i] + " " + days[i].ordinal());}// 将普通字符串转换为枚举实例System.out.println(Day.valueOf("THURSDAY"));// 获取枚举实例 SUNDAY 和 SATURDAYDay sunday = Day.SUNDAY;Day saturday = Day.SATURDAY;// 比较定义时的顺序System.out.println(sunday.compareTo(saturday));}
}

运行结果:

在使用 valueOf() 方法进行转换时,传递的名称必须与枚举常量的名字完全匹配(包括大小写),若不匹配,就会抛出 IllegalArgumentException 异常:

 当我们查看 java.lang.Enum 时:

可以看到,valueOf() 方法包含了两个类型的参数:Class<T> enumClass  和  String name

其中

Class<T> enumType 是一个 Class 对象,表示要查找的枚举类型

String name: 是一个字符串,表示要查找的枚举常量的名称。名称必须与枚举常量的名字完全匹配(包括大小写)

 但是在使用时,我们只传递了一个参数 name,也能够进行转换,这是为什么呢?

这是因为,在 Java 中,valueOf 方法实际上是自动生成的属于每个枚举类型的特性。虽然它的原始定义需要两个参数(类类型和名称),但是每个枚举类型都会自动提供一个与自身类型相关联的 valueOf 方法,只需传递一个字符串参数

因此,当我们调用 Day.valueOf("THURSDAY") 时,Java会自动处理这个调用,实际调用的是包含类名的 valueOf 方法,而不是原始的静态方法定义

再观察 java.lang.Enum:

我们会发现,其中并不存在 values() 这个方法,而当我们点击 values() 方法时,则会跳转到本类上

那么,values() 方法是从哪来的呢?

values() 方法是枚举类自动提供的一个静态方法,允许我们获取一个包含所有枚举常量的数组,这个方法是由Java编译器自动生成的,在编译时每个枚举类型都会自动生成一个 values() 方法,因此不需要我们显式定义它

我们将枚举类进行反编译:

(1)打开 cmd,切换到 Day.java 文件所在目录

(2)编译 .java 文件(javac Day.java)

(3)将 .class 文件进行反编译(javap -c Day.class > day.txt)

打开 day.txt,可以看到:

编译器自动为我们生成了 values 和 valueOf 方法

构造方法

当我们创建构造方法时:

 不能使用 public 来修饰构造方法,为什么呢?

这是因为,在 Java 中,枚举类的构造方法都是私有的(不加任何修饰符时,默认是 private),无法在枚举类外部调用,这也就防止了在枚举类外部创建新的枚举常量

在定义枚举常量时,构造方法会被隐式调用:

public enum Day {SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;Day() {System.out.println("构造方法");}public static void main(String[] args) {System.out.println("------------------");}
}

运行结果: 

 当我们定义带有参数的构造方法时,在创建枚举项时,也要为其提供对应参数:

public enum Day {SUNDAY("周天", 7),MONDAY("周一", 1),TUESDAY("周二", 2),WEDNESDAY("周三", 3),THURSDAY("周四", 4),FRIDAY("周五", 5),SATURDAY("周六", 6);private String name;private int key;Day(String name, int key) {this.name = name;this.key = key;}
}

枚举的优缺点

优点:

(1)枚举常量确保了只能使用定义的常量,避免了使用整型常量时可能带来的错误

(2)使用枚举可以使代码更易读,表达清晰

(3)枚举定义了一组固定的常量,适合表示有限的状态或选项,便于管理和维护

(4)枚举可以拥有字段、方法和构造方法,能够封装与常量相关的行为和属性

(5)Java的枚举类自带一些方法,如 values()、valueOf() 等

(6)可以用于 switch 语句

缺点:

(1)枚举的集合是固定的,无法在运行时添加或删除常量。如果需要动态的集合,枚举可能不适用

(2)枚举不能继承,无法扩展

(3)每个枚举常量都是一个对象,可能会增加内存使用,特别是当枚举常量数量较多时

枚举和反射

在 Java 反射-CSDN博客 中,我们学习了反射,通过反射,我们可以拿到类的私有构造方法,从而创建实例对象

那么,枚举是否可以通过反射,拿到实例对象呢?

public enum Day {SUNDAY("周天", 7),MONDAY("周一", 1),TUESDAY("周二", 2),WEDNESDAY("周三", 3),THURSDAY("周四", 4),FRIDAY("周五", 5),SATURDAY("周六", 6);private String name;private int key;Day(String name, int key) {this.name = name;this.key = key;}
}
public class Test {public static void main(String[] args) {Class<?> classDay = null;try {classDay = Class.forName("Day");Constructor<?> constructor = classDay.getDeclaredConstructor(String.class, int.class);constructor.setAccessible(true);Day day = (Day) constructor.newInstance("sunday", 0);System.out.println(day.ordinal());} catch (ClassNotFoundException e) {throw new RuntimeException(e);} 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);}}
}

运行结果:

此时程序抛出了 NoSuchMethodException 异常,也就是没有对应的构造方法

但是提供的枚举的构造方法就是带有两个参数,分别为 String 和 int:

那么,问题出在哪里呢?

自定义的枚举类默认继承自 java.lang.Enum

因此,自定义的枚举类继承了父类除构造方法外的所有东西,且子类需要帮助父类进行构造,

但我们实现的类中,并没有帮助父类进行构造

因此,我们需要在枚举类中帮助父类进行构造,而父类中的构造方法为:

那么,如何实现呢?通过 super 方法吗?

但是,当我们在构造方法中调用 super 时:

枚举构造方法中不能使用 super

 由于枚举比较特殊,在构造方法中,除了我们自定义了两个参数,它还默认添加了父类的两个参数

也就是说,构造函数中一共有四个参数:String int String int

其中,前两个参数是父类参数,后两个参数是子类参数

public class Test {public static void main(String[] args) {Class<?> classDay = null;try {classDay = Class.forName("enumDemo.Day");Constructor<?> constructor = classDay.getDeclaredConstructor(String.class, int.class, String.class, int.class);constructor.setAccessible(true);Day day = (Day) constructor.newInstance("父类参数", 0, "子类参数", 0);System.out.println(day.ordinal());} catch (ClassNotFoundException e) {throw new RuntimeException(e);} 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);}}
}

再次运行:

此时抛出了 IllegalArgumentException 异常,不能通过反射创建枚举对象

枚举保证了每个枚举常量只有一个实例,这种唯一性在枚举类型被定义时就已经确定,不允许外部创建新的实例,枚举类型的设计使得它们的实例在类加载时被唯一地定义,从而避免了通过反射创建新的枚举实例的可能性,确保了枚举的强类型安全性和唯一性

实现单例模式

在 单例模式:饿汉模式、懒汉模式_单例模式懒汉和饿汉-CSDN博客 中我们实现了单例模式,单例模式能够确保一个类只有一个实例

但普通类可以通过反射机制打破,因此,我们可以使用枚举来实现单例模式

public enum Singleton {INSTANCE;public Singleton getInstance() {return INSTANCE;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/8840.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【梯度下降法优化】随机梯度下降、牛顿法、动量法、Nesterov、AdaGrad、RMSprop、Adam

本文理论参考王木头的视频&#xff1a; “随机梯度下降、牛顿法、动量法、Nesterov、AdaGrad、RMSprop、Adam”&#xff0c;打包理解对梯度下降法的优化_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1r64y1s7fU/?spm_id_from333.999.0.0&vd_sourceecbdfcacb078d0…

五个高质量伤感视频素材资源站,帮你快速找到完美创作素材

在制作短视频、MV或者广告时&#xff0c;伤感主题的视频素材往往能触动观众的情感&#xff0c;让作品更具共鸣。无论是表达分手、离别&#xff0c;还是展现孤独与失落&#xff0c;合适的伤感素材对情感类创作至关重要。为帮助创作者找到优质的视频素材&#xff0c;以下推荐5个高…

天正建筑T20V8

链接: https://pan.baidu.com/s/1k-PcXJxHWPh3-6yAIfcaPg提取码: dvyn

JavaScript 实现文本转语音功能

全篇大概2000 字&#xff08;含代码&#xff09;&#xff0c;建议阅读时间10分钟。 引言 我将向大家展示如何使用 JavaScript 和 Web Speech API 快速实现一个“文本转语音”的 Web 应用。通过这个教程&#xff0c;你将了解如何让浏览器将输入的文本朗读出来。 预览效果 一、…

DNS域名详细解析详解

文章目录 DNS域名详细解析详解一、引言二、DNS域名解析过程1、DNS解析概述1.1、DNS解析的基本步骤 2、代码示例 三、DNS查询类型1、递归查询2、迭代查询 四、总结 DNS域名详细解析详解 一、引言 在互联网的世界里&#xff0c;域名和IP地址是两个不可或缺的概念。IP地址是计算…

函数计算——文档与网页数据提取工具(MinerU)应用实践

1 引言 在信息爆炸的时代&#xff0c;AI研究者面临着从海量文档中提取高质量数据的挑战。随着大语言模型在各个领域的广泛应用&#xff0c;有效地处理和整合文档信息成为了基础性的任务。这些文档形式多样&#xff0c;包括学术文献、行业报告、会议PPT、课本、说明书及合同单据…

【网络】应用层——HTTP协议

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;了解什么是HTTP协议。 > 毒鸡汤&#xff1a;有些事情&#xff0c;总是不明白&#xff0c;所以我不会坚持。早安! > 专栏选自&#xff1a;网络 &g…

计算生物学与生物信息学漫谈-5-mapping算法

之前的文章我们介绍了参考基因组&#xff0c;也介绍了一些基本概念&#xff0c;具体可以看之前的博客&#xff1a; 计算生物学与生物信息学漫谈-4-参考基因组与Mapping准备_基因组的map-CSDN博客 这次我们讲如何将read map到基因组上所用到的各种算法&#xff1a; 目录 1.1 …

qsqlmysql.lib的编译和使用

文章目录 打开源码 打开源码 打开qt源码安装路径 src相对路径下的文件Src\qtbase\src\plugins\sqldrivers\mysql 比如我是5.9.9版本我的路径就是&#xff1a;D:\Qt5.9.9\5.9.9\Src\qtbase\src\plugins\sqldrivers\mysql 可以看到待编译的mysql驱动文件 使用IDE打开pro文件进…

leetcode 693.交替位二进制数

1.题目要求&#xff1a; 2.题目代码: class Solution { public:bool hasAlternatingBits(int n) {int num n;//设置数组存入二进制位vector<int> array;while(num){array.push_back(num % 2); num num / 2;}//把数组颠倒就能得到此数真正二进制位reverse(array.begin…

IP协议知识点总结

IP协议主要分为三个 1. 地址管理 每个网络上的设备, 要能分配一个唯一的地址 2. 路由选择 小A 给小B 发消息, 具体应该走什么路线 3. 地址管理 IP 地址. 本质上是一个 32 位的整数 通常将, 32 位的整数使用点分十进制来表示, 如 192.168.1.1 一共可以表示 42 亿 9 千万个地址…

【重学 MySQL】八十二、深入探索 CASE 语句的应用

【重学 MySQL】八十二、深入探索 CASE 语句的应用 CASE语句的两种形式CASE语句的应用场景数据分类动态排序条件计算在 SELECT 子句中使用在 WHERE子句中使用在 ORDER BY 子句中使用 注意事项 在MySQL中&#xff0c;CASE 语句提供了一种强大的方式来实现条件分支逻辑&#xff0c…

机器学习1_机器学习定义——MOOC

一、机器学习定义 定义一 1959年Arthur Samuel提出机器学习的定义&#xff1a; Machine Learning is Fields of study that gives computers the ability to learn without being explicitly programmed. 译文&#xff1a;机器学习是这样的领域&#xff0c;它赋予计算机学习的…

充电桩--OCPP 充电通讯协议介绍

一、OCPP协议介绍 OCPP的全称是 Open Charge Point Protocol 即开放充电点协议&#xff0c; 它是免费开放的协议&#xff0c;该协议由位于荷兰的组织 OCA&#xff08;开放充电联盟&#xff09;进行制定。Open Charge Point Protocol (OCPP) 开放充电点协议用于充电站(CS)和任何…

如何制作公司小程序

我是【码云数智】平台的黄导&#xff0c;今天分享&#xff1a;如何制作公司小程序 企业小程序怎么制作&#xff0c;企业小程序制作不仅成为了连接消费者与品牌的桥梁&#xff0c;更是企业数字化转型的重要一环。 01、小程序制作流程 02、微信小程序开发多少钱 03、微信小程…

明道云正式发布国际品牌Nocoly

在2024年明道云伙伴大会上&#xff0c;明道云正式发布了其国际品牌Nocoly以及国际版产品Nocoly HAP。这标志着公司正式开启了海外业务。明道云的海外业务由全资拥有的Nocoly.com Limited经营&#xff0c;该公司注册在香港特别行政区。总部位于上海的明道云已经将围绕HAP超级应用…

如何构建一个可扩展的测试自动化框架?

以下为作者观点&#xff1a; 假设你是测试自动化方面的新手&#xff0c;想参与构建一个框架。在这种情况下&#xff0c;重要的是要了解框架所需的组件&#xff0c;以及它们是如何组合的。思考项目的具体需求和目标&#xff0c;以及可能遇到的困难和挑战。 假如你是一个测试架…

C++builder中的人工智能(11):双曲正切激活函数(ANN函数)?

在这篇文章中&#xff0c;我们将探讨双曲正切函数&#xff08;tanh&#xff09;是什么&#xff0c;以及如何在C中使用这个函数。让我们来回答这些问题。 在AI中激活函数意味着什么&#xff1f; 激活函数&#xff08;phi()&#xff09;&#xff0c;也称为转移函数或阈值函数&a…

基于SSM+VUE宠物医院后台管理系统JAVA|VUE|Springboot计算机毕业设计源代码+数据库+LW文档+开题报告+答辩稿+部署教+代码讲解

源代码数据库LW文档&#xff08;1万字以上&#xff09;开题报告答辩稿 部署教程代码讲解代码时间修改教程 一、开发工具、运行环境、开发技术 开发工具 1、操作系统&#xff1a;Window操作系统 2、开发工具&#xff1a;IntelliJ IDEA或者Eclipse 3、数据库存储&#xff1a…

二、SSM框架制作CRM系统案例

一、搭建框架 1、首先创建下面的目录结构 2、添加相关依赖&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-inst…