JavaSE进阶之(十六)枚举

news/2024/5/18 5:22:43 标签: java, 枚举, Enum, EnumMap, EnumSet

十六、枚举

16.1 背景

在 Java 语言中还没有引入枚举类型之前,表示枚举类型的常用模式是声明一组 int 类型的常量,常常用的就是:

java">public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int AUTUMN = 3;
public static final int WINTER = 4;

看似这样写是没有问题的,但是我们写代码的时候通常都会考虑到它的安全性、易用性和可读性。

首先是安全性。显然,这种模式并不是安全的。就拿上面的例子来说,我们根本无法保证传入值的合法性,在编译期和运行期不知道可能会出现什么情况,这就不符合 Java 程序的类型安全了。

其次是可读性。使用枚举类型的大多数场合都是为了方便得到枚举类型的描述(也就是字符串表达式),如果我们只是单一的打印出来这一组数字,也没有太大的用处。这时如果使用 String 来替代 int 作为常量,也不是不可以的,但是可能会导致性能问题,因为它依赖于字符串的比较操作。

从类型安全和程序可读性两方面考虑,int 和 String 枚举模式的缺点就暴露出来了。这时就引入了一个新的解决方案,就是枚举类型(enum type)

16.2 枚举类型

枚举(enum)是 Java 1.5 时引入的关键字,它标识一种特殊类型的类,继承自 java.lang.Enum,由一组固定的常量组成合法的类型。

新建一个枚举类 Season.java

java">/**
 * 季节枚举类
 *
 * @author qiaohaojie
 * @date 2023/3/22  14:07
 */
public enum Season {

    SPRING(1),
    SUMMER(2),
    AUTUMN(3),
    WINTER(4);

    private int code;

    Season(int code) {
        this.code = code;
    }

    public int getCode() {
        return code;
    }
}

其实在这个类中,我们并没有看到有继承关系的,来扒一下反编译后的字节码:

java">public final class Season extends Enum
{

    public static Season [] values()
    {
        return (Season [])$VALUES.clone();
    }

    public static Season valueOf(String name)
    {
        return (Season )Enum.valueOf(com/qhj/enumtype/Season, name);
    }

    private Season(String s, int i)
    {
        super(s, i);
    }

    public static final int SPRING;
	public static final int SUMMER;
	public static final int AUTUMN;
	public static final int WINTER;
	private static final Season $VALUES[];

    static 
    {
        SPRING= new Season ("SPRING", 0);
        SUMMER= new Season ("SUMMER", 1);
        AUTUMN= new Season ("AUTUMN", 2);
        WINTER= new Season ("WINTER", 3);
        $VALUES = (new Season[] {
            SPRING, SUMMER, AUTUMN, WINTER
        });
    }
}

Java 编译器帮我们做了很多隐式的工作:

  1. 要继承 Enum 类;
  2. 要写构造方法;
  3. 要声明静态变量和数组;
  4. 要用 static 块来初始化静态变量和数组;
  5. 要提供静态方法,比如 values() 和 valueOf(String name)。

作为开发者,我们的代码量减少了,枚举看起来简洁明了。

既然枚举是一种特殊的类,那么它其实是可以定义在一个类的内部的,这样它的作用域就可以限定于这个外部类中使用:

java">/**
 * 枚举定义在外部类中
 *
 * @author qiaohaojie
 * @date 2023/3/22  22:28
 */
public class SeasonClass {

    private Season season;

    public enum Season {

        SPRING(1),
        SUMMER(2),
        AUTUMN(3),
        WINTER(4);

        private int code;

        Season(int code) {
            this.code = code;
        }

        public int getCode() {
            return code;
        }
    }

    public boolean isSeason() {
        return getSeason() == Season.AUTUMN;
    }

    public Season getSeason() {
        return season;
    }

    public void setSeason(Season season) {
        this.season = season;
    }
}

Season 就相当于 SeasonClass 的内部类。

由于枚举是 final 的,所以可以确保在 Java 虚拟机中仅有一个常量对象,基于这个原因,我们可以使用 “==” 运算符来比较两个枚举是否相等,比如上面的 isSeason() 方法。

至于为什么不用 equals() 方法呢?

  1. 首先,“==” 运算符比较的时候,如果两个对象都为 null,并不会发生 NullPointerException,而 equals() 方法就会发生。
    在这里插入图片描述

  2. 另外,“==” 运算符会在编译时进行检查,如果两侧的类型不匹配,就会提示错误,而 equals() 方法则不会:在这里插入图片描述

另外,枚举还可以用于 switch 语句,和基本数据类型的用法一致:

java">public static String getChineseSeason(Season season) {
	 StringBuffer result = new StringBuffer();
	 switch (season) {
	     case SPRING:
	         result.append("[中文:春天,枚举常量:" + season.name() + ",数据:" + season.getCode() + "]");
	         break;
	     case SUMMER:
	         result.append("[中文:夏天,枚举常量:" + season.name() + ",数据:" + season.getCode() + "]");
	         break;
	     case AUTUMN:
	         result.append("[中文:秋天,枚举常量:" + season.name() + ",数据:" + season.getCode() + "]");
	         break;
	     case WINTER:
	         result.append("[中文:冬天,枚举常量:" + season.name() + ",数据:" + season.getCode() + "]");
	         break;
 }

如果枚举中需要包含更多信息的话,可以为其添加一些字段,比如:code、name 等,这时就需要为枚举添加一个带参的构造方法,这样就可以在定义枚举时添加对应的名称了。

EnumSet__EnumMap_171">16.3 EnumSet 和 EnumMap

EnumSet_172">01、EnumSet

EnumSet 是一个专门针对枚举类型的 Set 接口的实现类,它是处理枚举类型数据的一把利器,非常高效的。从名字上也可以看得出,EnumSet 不仅和 Set 有关系,也和枚举有关系。

因为 EnumSet 是一个抽象类,所以创建 EnumSet 时不能使用 new 关键字,但是 EnumSet 提供了很多有用的静态工厂方法。

举个例子,我们可以使用 noneOf) 静态工厂方法创建一个空的 Season 类型的 EnumSet;使用 allOf() 静态工厂方法创建一个包含所有 Season 类型的 EnumSet:

java">/**
 * @author qiaohaojie
 * @date 2023/3/22  22:41
 */
public class SeasonClassTest {
    public static void main(String[] args) {
        EnumSet<Season> enumSetNone = EnumSet.noneOf(Season.class);
        System.out.println(enumSetNone); // []

        EnumSet<Season> enumSetAll = EnumSet.allOf(Season.class);
        System.out.println(enumSetAll); // [SPRING, SUMMER, AUTUMN, WINTER]
    }
}

有了 EnumSet 后,就可以使用 Set 的一些方法了:
在这里插入图片描述

EnumMap_197">02、EnumMap

EnumMap 是一个专门针对枚举类型的 Map 接口的实现类,它可以将枚举常量作为键来使用。EnumMap 的效率甚至比 HashMap 还要高,可以直接通过数组下标(枚举的 ordinal 值)访问到元素。

EnumSet 不同的是,EnuMap 不是一个抽象类,所以创建 EnumMap 时可以使用 new 关键字:

java">/**
 * @author qiaohaojie
 * @date 2023/3/22  22:41
 */
public class SeasonClassTest {
    public static void main(String[] args) {
        EnumMap<Season, String> enumMap = new EnumMap<Season, String>(Season.class);
        enumMap.put(Season.SPRING, "春天");
        enumMap.put(Season.SUMMER, "夏天");
        enumMap.put(Season.AUTUMN, "秋天");
        enumMap.put(Season.WINTER, "冬天");
        System.out.println(enumMap); // {SPRING=春天, SUMMER=夏天, AUTUMN=秋天, WINTER=冬天}
    }
}

http://www.niftyadmin.cn/n/176593.html

相关文章

Linux下的coredump和kdump

目录前言coredump是什么&#xff1f;运行异常代码查看本地文件多出的core文件gdb调试带上core文件kdump机制前言 在我们之前介绍进程等待的时候&#xff0c;曾经介绍过父进程会等待子进程并且回收子进程的运行结束状态&#xff08;status输出型参数&#xff09;:参考博客 当进…

【思维模型】五分钟了解<第一性原理>,为什么学习第一性原理?什么是第一性原理?如何运用第一性原理?

【思维模型】五分钟了解<第一性原理>&#xff0c;为什么学习第一性原理&#xff1f;什么是第一性原理&#xff1f;如何运用第一性原理&#xff1f;1. 为什么学习第一性原理&#xff1f;2. 什么是第一性原理&#xff1f;3. 如何运用第一性原理&#xff1f;4. 小结参考&…

【零基础入门SpringBoot2】—— 核心功能_配置文件与Web开发

一、配置文件 &#x1f314; 1、什么是 yaml &#xff1f; YAML 是 “YAML Ain’t Markup Language”&#xff08;YAML 不是一种标记语言&#xff09;的递归缩写。在开发的这种语言时&#xff0c;YAML 的意思其实是&#xff1a;“Yet Another Markup Language”&#xff08;仍…

多输入多输出传递函数运算报错问题及其解决方案

MATLAB中两个多输入多输出的传递函数相除报错: 错误使用 / (第 65 行) In "SYS1/SYS2", the model SYS2 must have the same number of inputs as outputs. 这个错误提示是因为在MATLAB中,两个多输入多输出(MIMO)系统相除时,要求分子系统和分母系统具有相同的输…

华为OD机试题,用 Java 解【用户调度】问题 | 含解题说明

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典本篇题目:用户调度 题目 在通信系统中有…

输入圆的半径计算面积和周长-课后程序(JavaScript前端开发案例教程-黑马程序员编著-第2章-课后作业)

【案例2-5】输入圆的半径计算面积和周长 一、案例描述 考核知识点 toFixed()、isNaN、window.document对象 练习目标 掌握toFixed()方法。掌握数据类型检测。了解windoe.document对象。 需求分析 用JavaScript代码来计算圆的周长和面积&#xff0c;用户自己输入正确的r半径&…

Vue:路由管理模式

三种模式 Vue.js 的路由管理有三种模式&#xff1a; Hash 模式&#xff08;默认&#xff09;&#xff1a;在 URL 中使用 # 符号来管理路由。例如&#xff0c;http://example.com/#/about。这个模式的好处是可以避免浏览器向服务器发送不必要的请求&#xff0c;并且不需要特殊…

Windows系统可用的Dynv6 DDNS自动上报ipv4/ipv6工具

背景介绍 相信使用DDNS的小伙伴对Dynv6应该不陌生了吧~Dynv6官方网站提供了Linux脚本进行Dynv6 DDNS的ip更新&#xff0c;然而本人经过一番寻找&#xff0c;找不到适合Windows系统使用的工具~一气之下&#xff0c;经过七七四十九天的研发&#xff0c;开发出了一款Windows工具&…