关键字 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 的方法
@Overridepublic String toString() {return name().toLowerCase();}
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 随机选取
package com.paradise.think.enum19;import java.util.Random;/*** 随机选取** @author Paradise*/public class Enums {private static Random random = new Random(47);public static <T extends Enum<T>> T random(Class<T> tc) {return random(tc.getEnumConstants());}private static <T> T random(T[] values) {return values[random.nextInt(values.length)];}}enum Test {/*** 1*/One, Two, Three, Four, Five, Six;}class RandomTest {public static void main(String[] args) {System.out.println(Enums.random(Test.class));}}
虽然 Enum 只是一个相当短小的类,但是在本章你会发现,它能消除很多重复的代码。
重复总会制造麻烦,因此消除重复总是有益处的。
7 使用接口组织枚举
无法从 enum 继承子类有时很令人沮丧:这种需求有时源自
- 我们希望扩展原 enum 中的元素
- 我们希望使用子类将一个 enum 中的元素进行分组
在一个接口内部,创建实现该接口的枚举,以此将元素进行分组,可以达到将枚举元素分类组织的目的。
/*** 使用接口组织枚举;达到分类的目的** @author Paradise*/public interface Food {enum MainFood implements Food {/*** 面包*/Bread, Rice, Sandwich, Hamburger;}enum Coffee implements Food {/*** 纯咖啡*/PureCoffee, Blank, WHITE;}}
对于 enum 而言,实现接口是使其子类化的唯一办法;
——
创建一个“枚举的枚举”:创建一个新的 enum,然后用其实例包装 类型中的 每一个 enum类;
enum Course {/*** 主食*/MainFood(Food.MainFood.class),Coffee(Food.Coffee.class);private Food[] values;Course(Class<? extends Food> kind) {values = kind.getEnumConstants();}public Food select() {return Enums.random(values);}}
——
将一个 enum 嵌套在另一个 enum 内,仅仅是重新组织了一下代码,使你的代码具有更清晰的结构。
8 使用 EnumSet 替代标志
使用 EnumSet 的优点是:它在说明一个二进制位是否存在时,具有更好的表达能力,并且无需担心性能;
of() 方法被重载了很多次,接收2-5个显式的参数的情况都进行了重载,侧面反应了 EnumSet 对性能的关注;
EnumSet 的基础是 long,一个 long 值有 64位,而一个 enum 实例只需一位 bit 表示其是否存在。
if (universe.length <= 64)return new RegularEnumSet<>(elementType, universe);elsereturn new JumboEnumSet<>(elementType, universe);
9 使用 EnumMap
EnumMap 的速度很快;
命令设计模式;
与 EnumSet 一样, enum 实例定义的次序决定了其在 EnumMap 中的顺序
package com.paradise.think.enum19;import java.util.EnumMap;import java.util.Map;interface Command {/*** action*/void action();}/*** EnumMap** @author Paradise*/public class EnumMaps {public static void main(String[] args) {EnumMap<AlarmPoints, Command> enumMap = new EnumMap<>(AlarmPoints.class);enumMap.put(AlarmPoints.KITCHEN, () -> System.out.println(" Kitchen fire! "));enumMap.put(AlarmPoints.LOBBY, () -> System.out.println(" lobby fire! "));enumMap.put(AlarmPoints.OFFICE, () -> System.out.println(" Office fire! "));for (Map.Entry<AlarmPoints, Command> entry : enumMap.entrySet()) {System.out.println(entry.getKey());entry.getValue().action();}try {enumMap.get(AlarmPoints.STAIR1).action();} catch (Exception e) {System.out.println(e.toString());}}}
10 常量相关的方法

与使用匿名内部类相比较,定义常量相关方法的语法更搞笑,简洁。
10.1 使用 enum 的职责链
在 职责链 (Chain of Responsibility)设计模式中,程序员以多种不同的方式来解决一个问题,然后将它们链接在一起。当一个请求到来时,它遍历这个链,直到链中的某个解决方案能够处理该请求。
代码地址:
职责链 由 enum MailHandler 实现,而 enum 定义的次序决定了各个解决策略在应用时的次序。
