枚举Enum、映射EnumMap、集EnumSet

  • 一、枚举Enum
    • 1、概述
    • 2、介绍
      • ① valueOf
      • ② values
    • 3、分析
    • ※ 模仿一个枚举类
  • 二、枚举映射 EnumMap
    • 1、概述
    • 2、使用方法
    • 3、应用场景
  • 三、枚举集 EnumSet
    • 1、概述
    • 2、使用方法

本文使用 JDK 版本为 JDK1.15

一、枚举Enum

1、概述

一个集的枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。

  • Java的枚举本质上是一个特殊的类,它可以通过enum关键字定义。
  • 它可以定义构造器,但是不可被public修饰,所以不能被实例化。
  • 它的构造器只是在构造枚举值得时候被调用。
  • 它的内部也可以定义变量、方法。

2、介绍

枚举一般用于选择语句中,它提供的API如下:

为方便测试,我们定义这样的枚举类型:

public enum Color {WHITE,BLUE,GREEN,RED,YELLOW,BLACK //这里省略了分号,如果后续需定义其他成员,需加上分号
}

① valueOf

枚举一般应用于switch...case...default语句中,配合内置的valueOf方法提取字符串的值,具体使用案例如下:

public void whatColor(){switch (Color.valueOf("YELLOW")){case YELLOW:System.out.println("黄色");break;default:System.out.println("其他颜色");break;}
}

  • 当我们试图将一个 不存在的元素 的字符串作为 参数 时,会抛出异常:

java.lang.IllegalArgumentException: No enum constant Color.XXX

我们打印输出,进行测试:

System.out.println(Color.valueOf("vovo"));

② values

  • 枚举还提供了values方法,通过调用该方法,获取枚举类型内的所有内置元素,返回类型为一个枚举类型的数组(即Color类型):

我们打印输出

System.out.println(Arrays.toString(Color.values()));

  • 可以看到,我们按顺序取到了所有的元素值。
  • 那么,枚举类型的本质到底是什么?为什么没有返回 Object 类型 或是 String 类型 的数组?

3、分析

  • 为了探寻,枚举类型的本质,我们使用javap指令,对 Color.java 文件进行反编译:
  • 枚举类型本质上是一个继承自lang包下,Enum类的派生类。
  • 它默认拥有一个 values 数组、valueOf 方法,以及一个静态代码块。
  • 枚举类型的元素,本质上是与其相同类型的静态常量,只是名称有所不同 ,我们可以通过其名称获取相应的值。

※ 模仿一个枚举类

//Enum 类 不可被 我们随意 继承
public final class Color /*extends Enum<Color>*/{public static final Color WHITE;public static final Color BLUE;public static final Color GREEN;public static final Color RED;public static final Color YELLOW;public static final Color BLACK;static{WHITE = new Color("WHITE");BLUE = new Color("BLUE");GREEN = new Color("GREEN");RED = new Color("RED");YELLOW = new Color("YELLOW");BLACK = new Color("BLACK");}//定义变量colorprivate final String color;//私有的构造器private Color(String color) {this.color = color;}//静态方法 values();public static Color[] values() {return new Color[] {WHITE,BLUE,GREEN,RED,YELLOW,BLACK};}//静态方法 valueOf(String color);public static Color valueOf(String color) {switch (color) {case "WHITE":return Color.WHITE;case "BLUE":return Color.BLUE;case "GREEN":return Color.GREEN;case "RED":return Color.RED;case "YELLOW":return Color.YELLOW;case "BLACK":return Color.BLACK;default:throw new IllegalArgumentException("No enum constant: " + Color.class.getName() + "." + color);}}//为了防止其打印地址,我们只好重写toString方法,事实上enum类型并没有内置toString方法@Overridepublic String toString() {return this.color;}
}

上述类同样可以完成枚举类的功能,只是这样写十分繁琐,使用枚举类型可以帮助我们简化代码,而且看起来十分简洁明了。

二、枚举映射 EnumMap

1、概述

EnumMap是专门为枚举类型量身定做的Map实现,类似地还有EnumSet。虽然使用其它的Map实现(如HashMap)也能完成枚举类型实例到值得映射,但是使用EnumMap会更加高效:它只能接收同一枚举类型的实例作为键值,并且由于枚举类型实例的数量相对固定并且有限,所以EnumMap使用数组来存放与枚举类型对应的值。这使得EnumMap的效率非常高。

《Effective Java》中作者建议用EnumMap代替叙述索引,最好不要用序数来索引数组,而要使用EnumMap。

EnumMap构造方法采用键类型的Class对象:这是一个有限制的类型令牌,它提供了运行时的泛型信息。

其中Class<K>作为采用键类型的Class对象,说明EnumMap以枚举类型为键,可取出对应值。

2、使用方法

为方便说明,我们定义如下的星期Enum类,并创建对应的EnumMap:

enum Weekday{MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY
}

初始化 键值:

这是 Java 中 Map、Set 初始化设定数值的途径,形式上类似于数组{},Map与Set使用双层花括号定义初始数值{{}}

//初始化直接放入键值
Map<Weekday,String> map = new EnumMap<>(Weekday.class){{put(Weekday.MONDAY,"星期一");put(Weekday.TUESDAY,"星期二");put(Weekday.WEDNESDAY,"星期三");put(Weekday.THURSDAY,"星期四");put(Weekday.FRIDAY,"星期五");put(Weekday.SATURDAY,"星期六");put(Weekday.SUNDAY,"星期日");
}};

双层花括号的意义?

  • 外层花括号实际是定义了一个匿名内部类 (Anonymous Inner Class)。
  • 内层花括号实际上是一个实例初始化块 (instance initializer block),这个块在内部匿名类构造时被执行。这个块之所以被叫做“实例初始化块”是因为它们被定义在了一个类的实例范围内。

上面代码如果是写在 EnumMapDemo 类中,编译后你会看到会生成 EnumMapDemo$1.class 文件,编译 .java 文件后得到结果:

剖析这种方式,发现其本质上创建了一个继承 EnumMap 的匿名内部类(内部类概述):

// 第一个{}代表 创建了一个 HashMap 的子类
class EnumMapDemo$1<K extends Enum<K>, V> extends EnumMap { {   // 第二个{}中的代码放到了实例初始化块中去了put(Weekday.MONDAY, "星期一");put(Weekday.TUESDAY, "星期二");}EnumMapDemo$1(Class<K> keyType){  //super调用父类构造方法super(keyType); }
}

初始化后操作键值:

//先创建枚举映射
Map<Weekday,String> map = new EnumMap<>(Weekday.class);
//后放入键值
map.put(Weekday.MONDAY,"星期一");
map.put(Weekday.TUESDAY,"星期二");
map.put(Weekday.WEDNESDAY,"星期三");
map.put(Weekday.THURSDAY,"星期四");
map.put(Weekday.FRIDAY,"星期五");
map.put(Weekday.SATURDAY,"星期六");
map.put(Weekday.SUNDAY,"星期日");

3、应用场景

情景引入:
现有以 Java 语言编写的服务器、C# 语言 编写的客户端,二者为 C/S架构,均使用 Socket 进行通信。由于语言不相通,须手动构建请求、响应字符串,并指定状态码。

而数字难以识别,这时就可以在服务端使用 Enum 规定请求状态的英文、后以EnumMap<Enum,Integer>指定数字并以此做请求分类,简化我们的操作(图中:通信解析控制模块):

enum Status{ACCEPT,  //20RESPONSE,//50SERVER_CLOSING,//90RESOURCES_NOT_FOUND,//60ERROR,      //40SUCCESS     //70//...
}
Map<Status,Integer> statusMap = new EnumMap<>(Status.class){{put(Status.ACCEPT,20);put(Status.RESPONSE,50);put(Status.SERVER_CLOSING,90);put(Status.RESOURCES_NOT_FOUND,60);put(Status.ERROR,40);put(Status.SUCCESS,70);//...
}};

也可以将值包装成类,内部附有状态码、方法字符串,利用反射自动寻找、处理业务。

三、枚举集 EnumSet

1、概述

EnumSet 是一个枚举类型元素集的高效实现。枚举类型只有有限个例,所以EnumSet 内部用位序列实现。如果对应的值在集中,则相应的位被置为1。

2、使用方法

EnumSet类没用公共的构造器。可以使用静态工厂方法构造这个集:

enum Weekday{MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY
}
//全部值
EnumSet<Weekday> always = EnumSet.allOf(Weekday.class);
//无值
EnumSet<Weekday> never= EnumSet.noneOf(Weekday.class);
//范围值
EnumSet<Weekday> workday= EnumSet.range(Weekday.MONDAY,Weekday.FRIDAY);
//选中值
EnumSet<Weekday> mwf = EnumSet.of(Weekday.MONDAY,Weekday.SATURDAY,Weekday.FRIDAY)

⭐ E extends Enum 代表“E是一个枚举类型”。
⭐ 枚举类的特殊性正体现于此:所有的枚举类型都扩展于泛型 Enum 类(参考本文第一节)

【Java 枚举 集合】枚举类Enum、映射EnumMap、集EnumSet相关推荐

  1. java基础集合操作工具类Collections简述(java集合四)

    对集合中的元素进行排序 Collections中的sort方法使用 public class ListDemo {public static void main(String[] args) {Lis ...

  2. Java学习——集合ArrayList类

    1,集合ArrayList类底层就是用数组来实现的,其语法为: ArrayList objectName =new ArrayList<>(); 这个E一定要用引用数据类型 2,集合跟数组 ...

  3. Java—Set集合详解(HashSet/LinkedHashSet/TreeSet/EnumSet)

    关注微信公众号:CodingTechWork,一起学习进步. Set集合介绍 Set集合的概念   Set集合类似于一个容器,程序把很多对象保存到Set集合中,Set集合对添加顺序不记录,当有重复的对 ...

  4. Java技能树-集合-ArrayList类

    1 需求 2 接口 Class ArrayList<E> public class ArrayList<E> extends AbstractList<E> imp ...

  5. java.lang包—枚举类Enum

    原文作者:山高我为 原文地址:java enum的用法详解 目录 一.enum关键字 二.Enum类源码 三.疑问 四.Enum常见用法 一.enum关键字 enum关键字是在Java1.5也就是Ja ...

  6. enum java 比较_Kotlin与Java比较:枚举类

    前言 Kotlin作为JVM系的语言,起源于Java又不同于Java.通过在语言层面比较两者的区别,可以使得开发者能够快速学习,融会贯通. 枚举使用场景 使用枚举的场景非常明确,即只要一个类的对象是有 ...

  7. java arraylist枚举器遍历_Java基础(七)泛型数组列表ArrayList与枚举类Enum

    一.泛型数组列表ArrayList 1.在Java中,ArrayList类可以解决运行时动态更改数组的问题.ArrayList使用起来有点像数组,但是在添加或删除元素时,具有自动调节数组容量的功能,而 ...

  8. Java中的枚举类是什么?enum关键字怎么使用?

    枚举类 文章目录 枚举类 枚举类的使用:入门 自定义枚举类 方法一:自定义枚举类 方式二: enum 关键字定义枚举类(主要用该方式) Enum类的主要方法 使用enum关键字定义的枚举类实现接口 主 ...

  9. java枚举类Enum入门理解

    目录 枚举的定义 JDK5.0之前只能自定义枚举类 自定义枚举类的理解: JDK5.0之后enum关键字定义枚举类 区别于自定义枚举类 enum的父类Enum的常用方法 toString方法和valu ...

最新文章

  1. 【转】用示例说明索引数据块中出现热块的场景,并给出解决方案
  2. 创建型模式--原型模式
  3. SolrQuery的使用
  4. 8086汇编-实验8-jmp指令的理解
  5. Jenkins将致力于提升稳定性、易用性和云原生兼容性
  6. 如何获取sharepoint列表_练习 34 - 获取列表元素 - Learn Python 3 The Hard Way
  7. HBase 架构详解
  8. mac json工具_工具类封装的思路 | 钉钉群机器人为例
  9. CSS样式表书写位置
  10. 数据库开发 - 事务 死锁分析与解决
  11. Python 解leetcode:728. Self Dividing Numbers
  12. 书单丨把握Java技术发展的新趋势!
  13. android开源音乐播放器简单demo,Android开源在线音乐播放器——波尼音乐
  14. 【Unity3D进阶4-8】Unity3D 游戏框架
  15. ISSCC2021 基于SRAM的存内计算16.3阅读记录
  16. Bootstrap(一)
  17. ural 1671 Anansi's Cobweb
  18. 使用EasyExcel下载,文件名乱码问题处理
  19. linux运行lnk,LNK 文件扩展名: 它是什么以及如何打开它?
  20. 国外lead教程---EMU之SSN用不用

热门文章

  1. NAR-2018-dbCAN2鉴定宏基因组CAZYome碳水化合物相关基因
  2. 【3D商城】添加商品产品模型
  3. [易飞]供应商料件特殊检验方式优先级大于检验方式
  4. Android系统目录介绍
  5. LTE(4G) VOLTE协议栈架构
  6. 005day(扣丁课堂色块搭建)
  7. Hadoop应用场景
  8. android build.prop文件
  9. skywalking9.2
  10. 1×pbs缓冲液配方_PBS缓冲液的配方 - 资料中心 - 生物在线