十三、枚举

文章目录

  • 枚举
    • 4.1 基础
    • 4.2 实现枚举
    • 4.3 自定义枚举

枚举

本文为书籍《Java编程的逻辑》1和《剑指Java:核心原理与应用实践》2阅读笔记

枚举是一种特殊的数据,它的取值是有限的,是可以枚举出来的,比如一年有四季、一周有七天。

4.1 基础

定义和使用基本的枚举是比较简单的,我们来看个例子。为表示一年四季,我们定义一个枚举类型Season,包括四个季节:春、夏、秋、冬,代码如下:

package com.ieening.learnEnum;public enum Season {SPRING, SUMMER, AUTOM, WINTER;
}

枚举使用enum这个关键字来定义,Season包括四个值,分别表示春、夏、秋和冬,值一般是大写的字母,多个值之间以逗号分隔。枚举类型可以定义为一个单独的文件,也可以定义在其他类内部。

可以这样使用Season

Season season = Season.SPRING

Season season声明了一个变量season,它的类型是Seasonseason = Season.SPRING将枚举值SPRING赋值给season变量。枚举变量的toString方法返回其字面值,所有枚举类型也都有一个name方法,返回值与toString一样。

    @Testpublic void testEnumToString() {assertEquals("SPRING", Season.SPRING.toString());}@Testpublic void testEnumName() {assertEquals("SPRING", Season.SPRING.name());}

输出都是SPRING。枚举变量可以使用equals==进行比较,结果是一样的,例如:

    @Testpublic void testEnumEquals() {Season summer = Season.SUMMER;assertTrue(summer == Season.SUMMER);assertTrue(summer.equals(Season.SUMMER));assertFalse(summer == Season.AUTOM);}

枚举值是有顺序的,可以比较大小。枚举类型都有一个方法int ordinal(),表示枚举值在声明时的顺序,从 0 0 0开始,例如,如下代码输出为 1 1 1​:

    @Testpublic void testEnumOrdinal() {assertTrue(0 == Season.SPRING.ordinal());assertTrue(1 == Season.SUMMER.ordinal());assertTrue(2 == Season.AUTOM.ordinal());assertTrue(3 == Season.WINTER.ordinal());}

另外,枚举类型都实现了Java API中的Comparable接口,都可以通过方法compareTo与其他枚举值进行比较。比较其实就是比较ordinal的大小,例如,如下代码:

    @Testpublic void testEnumComparable() {Season summer = Season.SUMMER;assertEquals(1, summer.compareTo(Season.SPRING));assertEquals(-1, summer.compareTo(Season.AUTOM));}

枚举变量可以用于和其他类型变量一样的地方,如方法参数、类变量、实例变量等。枚举还可以用于switch语句。在switch语句内部,枚举值不能带枚举类型前缀,例如,直接使用SPRING,不能使用Season.SPRING

枚举类型都有一个静态的valueOf(String)方法,可以返回字符串对应的枚举值;枚举类型也都有一个静态的values方法,返回一个包括所有枚举值的数组,顺序与声明时的顺序一致。

    @Testpublic void testEnumValueOf() {assertEquals(Season.SPRING, Season.valueOf("SPRING"));}@Testpublic void testEnumValues() {assertArrayEquals(new Season[] { Season.SPRING, Season.SUMMER, Season.AUTOM, Season.WINTER }, Season.values());}

枚举的好处体现在以下几方面。

  1. 定义枚举的语法更为简洁。
  2. 枚举更为安全。一个枚举类型的变量,它的值要么为null,要么为枚举值之一,不可能为其他值,但使用整型变量,它的值就没有办法强制,值可能就是无效的。
  3. 枚举类型自带很多便利方法(如valuesvalueOftoString等),易于使用。

4.2 实现枚举

枚举是怎么实现的呢?枚举类型实际上会被Java编译器转换为一个对应的类,这个类继承了Java API中的java.lang.Enum类。Enum类有nameordinal两个实例变量,在构造方法中需要传递,name()toString()ordinal()compareTo()、equals()方法都是由Enum类根据其实例变量nameordinal实现的。valuesvalueOf方法是编译器给每个枚举类型自动添加的。下面是Enum类代码。

public abstract class Enum<E extends Enum<E>> implements Constable, Comparable<E>, Serializable {private final String name;private final int ordinal;public final String name() {return this.name;}public final int ordinal() {return this.ordinal;}protected Enum(String var1, int var2) {this.name = var1;this.ordinal = var2;}public String toString() {return this.name;}public final boolean equals(Object var1) {return this == var1;}public final int hashCode() {return super.hashCode();}protected final Object clone() throws CloneNotSupportedException {throw new CloneNotSupportedException();}public final int compareTo(E var1) {if (this.getClass() != var1.getClass() && this.getDeclaringClass() != var1.getDeclaringClass()) {throw new ClassCastException();} else {return this.ordinal - var1.ordinal;}}public final Class<E> getDeclaringClass() {Class var1 = this.getClass();Class var2 = var1.getSuperclass();return var2 == Enum.class ? var1 : var2;}public final Optional<EnumDesc<E>> describeConstable() {return this.getDeclaringClass().describeConstable().map((var1) -> {return java.lang.Enum.EnumDesc.of(var1, this.name);});}public static <T extends Enum<T>> T valueOf(Class<T> var0, String var1) {Enum var2 = (Enum)var0.enumConstantDirectory().get(var1);if (var2 != null) {return var2;} else if (var1 == null) {throw new NullPointerException("Name is null");} else {throw new IllegalArgumentException("No enum constant " + var0.getCanonicalName() + "." + var1);}}protected final void finalize() {}private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {throw new InvalidObjectException("can't deserialize enum");}private void readObjectNoData() throws ObjectStreamException {throw new InvalidObjectException("can't deserialize enum");}
}

4.3 自定义枚举

以上枚举用法是最简单的,实际中枚举经常会有关联的实例变量和方法。比如,衣服Size例子,每个枚举值可能有关联的缩写和中文名称,可能需要静态方法根据缩写返回对应的枚举值,代码如下:

public enum Size {SMALL("S", "小号"),MEDIUM("M", "中号"),LARGE("L", "大号");private String abbr;private String title;private Size(String abbr, String title){this.abbr = abbr;this.title = title;}public String getAbbr() {return abbr;}public String getTitle() {return title;}public static Size fromAbbr(String abbr){for(Size size : Size.values()){if(size.getAbbr().equals(abbr)){return size;}}return null;}
}

上述代码定义了两个实例变量abbrtitle,以及对应的get方法,分别表示缩写和中文名称;定义了一个私有构造方法,接受缩写和中文名称,每个枚举值在定义的时候都传递了对应的值;同时定义了一个静态方法fromAbbr,根据缩写返回对应的枚举值。需要说明的是,枚举值的定义需要放在最上面,枚举值写完之后,要以分号(;)结尾,然后才能写其他代码。

每个枚举值经常有一个关联的标识符(id),通常用int整数表示,使用整数可以节约存储空间,减少网络传输。一个自然的想法是使用枚举中自带的ordinal值,但ordinal值并不是一个好的选择。为什么呢?因为ordinal值会随着枚举值在定义中的位置变化而变化,但一般来说,我们希望id值和枚举值的关系保持不变,尤其是表示枚举值的id已经保存在了很多地方的时候。比如,上面的Size例子,Size.SMALLordinal值为 0 0 0,我们希望 0 0 0表示的就是Size.SMALL,但如果增加一个表示超小的值ⅩSMALL

public enum Size {XSMALL, SMALL, MEDIUM, LARGE
}

这时, 0 0 0就表示ⅩSMALL了。所以,一般是增加一个实例变量表示id。使用实例变量的另一个好处是,id可以自己定义。比如,Size例子可以写为:

public enum Size {XSMALL(10), SMALL(20), MEDIUM(30), LARGE(40);private int id;private Size(int id){this.id = id;}public int getId() {return id;}
}

枚举还有一些高级用法,比如,每个枚举值可以有关联的类定义体,枚举类型可以声明抽象方法,每个枚举值中可以实现该方法,也可以重写枚举类型的其他方法。此外,枚举可以实现接口,也可以在接口中定义枚举。

package com.ieening.learnEnum;public enum SeasonEnum {SPRING(1) {@Overridepublic String description() {return "最是平常百姓家,新竹半掩几春花。门前犬吠鸣鸭远,老汉低眉啜现茶。";}},SUMMER(2) {@Overridepublic String description() {return "树梢挑月伏南窗,梦随清风玉枕凉。了断新愁千缕结,池塘半锁藕花香。";}},AUTOM(3) {@Overridepublic String description() {return "廊桥雁断树栖鸦,柳水秋枫揽碧霞。斜阳晚照无限好,诗茶伴雨写霜花。";}},WINTER(4) {@Overridepublic String description() {return "玉蝶飘飞压翠枝,红梅初笑恨未迟。晨风落雪轻妙舞,月照西窗斌小诗。";}};private int id;public int getId() {return id;}private SeasonEnum(int id) {this.id = id;}public static SeasonEnum fromId(int id) {for (SeasonEnum seasonEnum : SeasonEnum.values()) {if (id == seasonEnum.id) {return seasonEnum;}}return null;}public abstract String description();
}

  1. 马俊昌.Java编程的逻辑[M].北京:机械工业出版社,2018. ↩︎

  2. 尚硅谷教育.剑指Java:核心原理与应用实践[M].北京:电子工业出版社,2023. ↩︎

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法导论记录丨16.1 活动选择、877. 石子游戏

16.1 活动选择 最优子结构 活动选择问题的最优子结构意味着问题的最优解包含了其子问题的最优解。具体来说&#xff0c;如果我们有一个按结束时间排序的活动集合 S{a1​,a2​,...,an​}&#xff0c;并且 S’ 是 S 的最大兼容活动子集&#xff0c;那么对于 S′ 中的任何活动aj…

COW AI接入到微信 保姆教程 (部署在服务器,插件安装)

此文章不涉及国外的AI模型&#xff0c;也无需翻墙&#xff0c;跟某AI模型无关&#xff0c;审核大哥别弄错了 最近的AI开始越开越火了&#xff0c;开始介入到我们生活中的方方面面。就有人好奇AI是否能接入到微信吗&#xff1f;我在GitHub上搜索的时候还真有除了对话外还可以通…

MySQL 基础知识(五)之数据增删改

目录 1 插入数据 2 删除数据 3 更改数据 创建 goods 表 drop table if exists goods; create table goods ( id int(10) primary key auto_increment, name varchar(14) unique, stockdate date )charsetutf8; 1 插入数据 当要插入的数据为日期/时间类型时&#xff0c;如果…

Spring Boot 笔记 021 项目部署

1.1 引入坐标&#xff0c;并双击package打包成jar包 1.2 在服务器上运行jar包 1.3 使用postman测试 2.1 运行配置 2.1.1 命令更改端口 java -jar big-event-1.0-SNAPSHOT.jar --server.port7777 2.1.2 环境变量更新&#xff08;略&#xff09; 2.1.3 外部配置文件&#xff0c…

日期类运算符重载以及const成员详细解析

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言进阶 数据结构初阶 Linux C初阶 算法 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂 目录 一.前言 二.运算符重载 2.1概念 2.2比较的符号重载 2.2.1…

。ldewd

学习目标&#xff1a; 提示&#xff1a;这里可以添加学习目标 例如&#xff1a; 一周掌握 Java 入门知识 学习内容&#xff1a; 提示&#xff1a;这里可以添加要学的内容 例如&#xff1a; 搭建 Java 开发环境掌握 Java 基本语法掌握条件语句掌握循环语句 学习时间&#x…

ZBX_NOTSUPPORTED: Unsupported item key. 原因排查

进行自定义监控项时&#xff0c;在zabbix-agent端测试没问题&#xff0c;却在zabbix-server进行测试时&#xff0c;出现 ZBX_NOTSUPPORTED: Unsupported item key. 1.在zabbix-agent测试没问题&#xff0c;证明自定义监控项的脚本没问题&#xff0c;却在zabbix-server端测试出…

点击侧边栏菜单时只切换 <router-view> 中的内容,而不是进行整个页面的路由跳转(动态路由)

解决方法&#xff1a;在 <el-menu> 的 select 事件中调用了 handleMenuSelect 方法来处理菜单项的选择。你可以在 handleMenuSelect 方法中根据菜单项的 index 来执行相应的操作&#xff0c;例如更新组件内的数据或者切换组件。由于整个页面的路由路径并没有改变&#xf…

平时积累的FPGA知识点(7)

平时在FPGA群聊等积累的FPGA知识点&#xff0c;第七期&#xff1a; 11 描述扇出的xilinx官方文档是&#xff1f; 解释&#xff1a;ug949 12 在BD中如何指定某个IP用global&#xff0c;其他的用OOC模式&#xff1f;因为某个模块引用的IP带着XPM&#xff0c;综合不了 解释&am…

代码随想录Day50 | 70. 爬楼梯 322. 零钱兑换 279.完全平方数

代码随想录Day50 | 70. 爬楼梯 322. 零钱兑换 279.完全平方数 70.爬楼梯322.零钱兑换279.完全平方数 70.爬楼梯 文档讲解&#xff1a;代码随想录 视频讲解&#xff1a; 状态 dp数组 dp[j]表示爬上第j阶台阶需要的方法数递推公式&#xff0c;由于在每一阶台阶可以向上走1~m阶&a…

RocketMQ与Kafka深度对比:特性与适用场景解析

在分布式系统中&#xff0c;消息队列作为解耦、缓冲和异步通信的关键组件&#xff0c;其选择对于系统的性能和稳定性至关重要。RocketMQ和Kafka作为两款流行的开源消息中间件&#xff0c;各自拥有独特的设计理念和功能特性。本文将详细对比RocketMQ与Kafka在数据可靠性、实时性…

代码随想录算法训练营Day57|647. 回文子串、516.最长回文子序列、动态规划总结

目录 647. 回文子串 前言 思路 算法实现 516.最长回文子序列 前言 思路 算法实现 动态规划总结 动规五部曲回顾 动规各小专题问题 647. 回文子串 题目链接 文章链接 前言 本题利用动态规划求解时&#xff0c;dp数组的定义与前面的就有些不同了&#xff0c;是难点之…

随机过程及应用学习笔记(三)几种重要的随机过程

介绍独立过程和独立增量过程。重点介绍两种独立增量过程-—维纳过程和泊松过程。 目录 前言 一、独立过程和独立增量过程 1、独立过程&#xff08;Independent Process&#xff09; 2、独立增量过程&#xff08;Independent Increment Process&#xff09; 二、正态过程&am…

Python bytes 类型的可变版本——bytearray类型

bytearray 是 Python 中的一个内置类型&#xff0c;用于表示可变长度的字节序列。它是 bytes 类型的可变版本&#xff0c;即 bytearray 实例的内容可以修改&#xff0c;而 bytes 实例是不可变的。 创建 bytearray 的方式&#xff1a; 通过构造函数创建&#xff1a;可以通过传递…

幻兽帕鲁云服务器机型推荐配置,支持6个人以内/10个人/20个人以内的配置怎么选择?

如果是6个人以下&#xff0c;比较建议4核16G的这个服务器配置。如果人数更多&#xff0c;就选8核32G这个配置&#xff0c;或者更高&#xff0c;如果是20个人以上&#xff0c;那么就得16核64G35M这样或者更高的配置了。 参考&#xff1a; 4~8人&#xff1a;推荐4核16G&#xf…

debug - 打补丁 - 浮点数加法

文章目录 debug - 打补丁 - 浮点数加法概述笔记demo用CE查看汇编(x64debug)main()update_info()快捷键 - CE中查看代码时的导航打补丁的时机 - 浮点数加法补丁代码补丁效果浮点数寄存器组的保存END debug - 打补丁 - 浮点数加法 概述 在cm中, UI上显示的数值仅仅用来显示, 改…

力扣---通配符匹配

题目描述&#xff1a; 给你一个输入字符串 (s) 和一个字符模式 (p) &#xff0c;请你实现一个支持 ? 和 * 匹配规则的通配符匹配&#xff1a; ? 可以匹配任何单个字符。 * 可以匹配任意字符序列&#xff08;包括空字符序列&#xff09;。 判定匹配成功的充要条件是&#xff…

华为23年9月笔试原题,巨详细题解,附有LeetCode测试链接

文章目录 前言思路主要思路关于f函数的剖析Code就到这&#xff0c;铁子们下期见&#xff01;&#xff01;&#xff01;&#xff01; 前言 铁子们好啊&#xff01;今天阿辉又给大家来更新新一道好题&#xff0c;下面链接是23年9月27的华为笔试原题&#xff0c;LeetCode上面的ha…

《软件质量保证与测试》单元测试:使用单元测试工具 JUnit 测试自定义的类

文章目录 前言一、实验目的二、实验内容三、实验步骤和结果3.1、建立需要进行 JUnit 测试的类 StringUtil3.2、建立对应的 JUnit Test 类 StringUtilTest3.3、添加 JUnit 测试信息3.4、生成测试代码3.5、assertEquals 方法介绍3.6、使用 assertEquals 方法进行单元测试3.7、执行…

开源≠不赚钱,开源软件盈利的7大模式。

开源不是目的&#xff0c;目的是圈用户&#xff0c;留住用户&#xff0c;盈利自然不成问题。 开源系统可以通过多种方式赚钱&#xff0c;以下是其中几种常见的方式&#xff1a; 提供付费支持&#xff1a; 开源系统可以提供付费的技术支持服务&#xff0c;包括安装、配置、维…