枚举类的高阶用法
之前在 单例模式 这一篇中有提到可以使用枚举实现单例,并简单介绍了一下原理,这里讲讲平时在开发中使用枚举的一些常见姿势,学以致用!
关于枚举的一些知识点
枚举 enum 关键字是在 Java 5 中引入,是隐式继承自 java.lang.Enum
的一种特殊的类,通常被用于常量定义,相对于 public static final
这种方式,使用枚举常量可以使代码更易读、支持编译时类型检测避免非法参数等好处,此外枚举类型还自带一些有用的方法可直接使用。下面是枚举类型的一些特点:
所有的枚举类都隐式的继承了 Enum 抽象类,因此无法再继承其它类,但是可以实现接口;但是你自己却不能显示的定义一个继承了 Enum 的类,Javac 编译器禁止这种行为
枚举类是类型安全的,你不能给一个指向枚举的引用赋值其它任何类型的变量
可以通过
MyEnum.values()
获取到所有该枚举类型的实例数组,其顺序与定义的顺序保持一致;ordinal() 方法则返回枚举在该数组中的下标Enum 常量隐式的是 static 和 final 的,这个可以从之前的字节码解析文件中看到
Enum 可以直接使用
==
比较,这时因为 enum types ensure that only one instance of the constants exist in the JVM可以用于 switch 语句
Enum 实例只能从内部创建而不能通过 new 创建,因为其构造函数是私有的
Enum 实例会在其第一次被调用/引用的时候创建,这也是使用枚举实现单例模式懒加载的原理
枚举用于定义常量
1 | public enum GenderEnum { |
支持定义方法,同时支持方法的重写
1 | public enum ColorEnum { |
通过 javac 编译该枚举可以得到三个 class 文件:ColorEnum$1.class ColorEnum$2.class ColorEnum.class
。再次执行 javap -v ColorEnum$1.class
可以看到一行 public class ColorEnum extends java.lang.Enum<ColorEnum>
,可知 RED 和 BLUE 其实是 ColorEnum 类的匿名内部类,他们都继承了 ColorEnum 类,因此是子类对父类方法的重写。但是注意 Enum 类都是 final 的,按理说不能够被继承,从现象来看可能是编译器对内部类继承 final 类的限制有所不同。
通过实现接口对枚举进行分组
我们知道枚举类不能被继承,因为它是 final 的,那么枚举类能继承其它类吗?答案也是不能,因为其已经隐式的继承了 Enum 抽象类,但是这对枚举类实现接口没有任何限制,因此可能通过实现接口对同一类枚举进行分组,同时用接口去规范枚举类里面的方法。
1 | public interface Food { |
EnumSet
The EnumSet is a specialized Set implementation meant to be used with Enum types.
EnumSet 是专门为枚举常量设计的一种集合实现,针对枚举类 EnumSet 要比 HashSet 的效率更高,因为它底层使用了 Bit Vector Representation
的结构。EnumSet 是一个抽象类,有 2 个默认实现 RegularEnumSet
和 JumboEnumSet
,内部会根据常量的数量在两者之间自动转换。
EnumMap
如果 Map 的 Key 类型是枚举类型的话, 相比于 HashMap,更推荐使用 EnumMap。EnumMap 的 key 只能是 Enum 类,底层实现是基于数组的。一般用于保存一个枚举类对应的额外的业务信息。
使用枚举实现单例
参考之前的文章 枚举方式实现单例
使用枚举实现策略模式
传统的策略模式是定义一个接口,然后不同的策略是不同的实现类,这就意味着每新增一种策略就需要新增一个实现类。如果通过枚举类实现策略模式的话则只需要增加一个枚举常量即可。
1 | public enum PizzaDeliveryStrategy { |