关键字 enum 可以将一组具名的值的有限集合创建为一种新的类型。

1 基本 enum 特性

values() -> 返回枚举实例数组,并且是声明时的顺序;

ordinal() -> 返回一个 int 值,实例声明时的次序,从 0 开始;

Enum 类 实现了 Comparable 接口 和 Serializable 接口,具有 CompareTo() 方法;

name() toString() 返回实例声明时的名字

valueOf() 是在 Enum 中定义的 static 方法,根据给定的名字返回相应的 enum 实例;

将静态导入用于 enum import static com.paradise.think.enum19.Season.*;

static import 静态导入 有使用过,IDE有时会建议

2 向 enum 中添加新方法

除了不能继承自一个 enum 之外,我们基本上可以将 enum 看作一个常规的类。

只能在 enum 定义的内部使用其构造器创建 enum 实例。
一旦 enum 的定义结束,编译器就不允许我们再使用其构造器来创建任何实例了。

2.1 覆盖 enum 的方法

  1. @Override
  2. public String toString() {
  3. return name().toLowerCase();
  4. }

3 switch 语句中的 enum

一般来说,在 switch 中只能使用整数值,而枚举实例天生就具备整数值的次序。

虽然一般情况下我们必须使用 enum 类型来修饰一个 enum 实例,但是在 case 语句中却不必如此。

4 values() 的神秘之处

values() 是由编译器添加的 static 方法,同时还添加了 valueOf(String) 方法;

由于 values() 方法是由编译器插入到 enum 定义中的 static 方法,所以,如果你将 enum 实例向上转型为 Enum,那么 values() 方法就不可访问了。不过,在 Class 中有一个 getEnumConstants() 方法,可以通过 Class 对象取得 所有 enum 实例

5 实现,而非继承

所有的 enum 都继承自 java.lang.Enum 类;
Java 不支持多重继承;

可以实现一个或多个接口;

6 随机选取

  1. package com.paradise.think.enum19;
  2. import java.util.Random;
  3. /**
  4. * 随机选取
  5. *
  6. * @author Paradise
  7. */
  8. public class Enums {
  9. private static Random random = new Random(47);
  10. public static <T extends Enum<T>> T random(Class<T> tc) {
  11. return random(tc.getEnumConstants());
  12. }
  13. private static <T> T random(T[] values) {
  14. return values[random.nextInt(values.length)];
  15. }
  16. }
  17. enum Test {
  18. /**
  19. * 1
  20. */
  21. One, Two, Three, Four, Five, Six;
  22. }
  23. class RandomTest {
  24. public static void main(String[] args) {
  25. System.out.println(Enums.random(Test.class));
  26. }
  27. }

虽然 Enum 只是一个相当短小的类,但是在本章你会发现,它能消除很多重复的代码。
重复总会制造麻烦,因此消除重复总是有益处的。

7 使用接口组织枚举

无法从 enum 继承子类有时很令人沮丧:这种需求有时源自

  • 我们希望扩展原 enum 中的元素
  • 我们希望使用子类将一个 enum 中的元素进行分组

在一个接口内部,创建实现该接口的枚举,以此将元素进行分组,可以达到将枚举元素分类组织的目的。

  1. /**
  2. * 使用接口组织枚举;达到分类的目的
  3. *
  4. * @author Paradise
  5. */
  6. public interface Food {
  7. enum MainFood implements Food {
  8. /**
  9. * 面包
  10. */
  11. Bread, Rice, Sandwich, Hamburger;
  12. }
  13. enum Coffee implements Food {
  14. /**
  15. * 纯咖啡
  16. */
  17. PureCoffee, Blank, WHITE;
  18. }
  19. }

对于 enum 而言,实现接口是使其子类化的唯一办法;
——
创建一个“枚举的枚举”:创建一个新的 enum,然后用其实例包装 类型中的 每一个 enum类;

  1. enum Course {
  2. /**
  3. * 主食
  4. */
  5. MainFood(Food.MainFood.class),
  6. Coffee(Food.Coffee.class);
  7. private Food[] values;
  8. Course(Class<? extends Food> kind) {
  9. values = kind.getEnumConstants();
  10. }
  11. public Food select() {
  12. return Enums.random(values);
  13. }
  14. }

——
将一个 enum 嵌套在另一个 enum 内,仅仅是重新组织了一下代码,使你的代码具有更清晰的结构。

8 使用 EnumSet 替代标志

使用 EnumSet 的优点是:它在说明一个二进制位是否存在时,具有更好的表达能力,并且无需担心性能;

of() 方法被重载了很多次,接收2-5个显式的参数的情况都进行了重载,侧面反应了 EnumSet 对性能的关注;

EnumSet 的基础是 long,一个 long 值有 64位,而一个 enum 实例只需一位 bit 表示其是否存在。

  1. if (universe.length <= 64)
  2. return new RegularEnumSet<>(elementType, universe);
  3. else
  4. return new JumboEnumSet<>(elementType, universe);

EnumSet 的源码分析:
位运算之类的需要突破 ~~

9 使用 EnumMap

EnumMap 的速度很快;

命令设计模式;

与 EnumSet 一样, enum 实例定义的次序决定了其在 EnumMap 中的顺序

  1. package com.paradise.think.enum19;
  2. import java.util.EnumMap;
  3. import java.util.Map;
  4. interface Command {
  5. /**
  6. * action
  7. */
  8. void action();
  9. }
  10. /**
  11. * EnumMap
  12. *
  13. * @author Paradise
  14. */
  15. public class EnumMaps {
  16. public static void main(String[] args) {
  17. EnumMap<AlarmPoints, Command> enumMap = new EnumMap<>(AlarmPoints.class);
  18. enumMap.put(AlarmPoints.KITCHEN, () -> System.out.println(" Kitchen fire! "));
  19. enumMap.put(AlarmPoints.LOBBY, () -> System.out.println(" lobby fire! "));
  20. enumMap.put(AlarmPoints.OFFICE, () -> System.out.println(" Office fire! "));
  21. for (Map.Entry<AlarmPoints, Command> entry : enumMap.entrySet()) {
  22. System.out.println(entry.getKey());
  23. entry.getValue().action();
  24. }
  25. try {
  26. enumMap.get(AlarmPoints.STAIR1).action();
  27. } catch (Exception e) {
  28. System.out.println(e.toString());
  29. }
  30. }
  31. }

10 常量相关的方法

image.png

与使用匿名内部类相比较,定义常量相关方法的语法更搞笑,简洁。

10.1 使用 enum 的职责链

在 职责链 (Chain of Responsibility)设计模式中,程序员以多种不同的方式来解决一个问题,然后将它们链接在一起。当一个请求到来时,它遍历这个链,直到链中的某个解决方案能够处理该请求。

代码地址:

职责链 由 enum MailHandler 实现,而 enum 定义的次序决定了各个解决策略在应用时的次序。

10.2 使用 enum 的状态机

枚举类型非常适合用来创建 状态机

11 多路分发

11.1 使用 enum 分发

11.2 使用常量相关的方法

11.3 使用 EnumMap 分发

11.4 使用二维数组

12 总结