文章目录
- 深入理解枚举类
- 简介
- 枚举的好处
- 枚举的典型应用
- 使用规范
- 枚举的本质
- 枚举类的声明
- 枚举的方法
- 枚举的特性
- 基本特性
- 枚举可以添加方法
- 枚举可以添加普通方法、静态方法、抽象方法、构造方法
- 枚举可以实现接口
- 枚举的应用
- 组织常量
- 状态机
- 错误码
- 组织枚举
- 枚举工具类
- EnumSet
- EnumMap
- 参考资料
深入理解枚举类
简介
enum
全称是 enumeration,是 JDK1.5 引入的新特性,位于Java.lang
包下。
在Java中 enum
是一个关键字,被 enum
修饰的类型就是枚举类。
public enum ColorEnum{
BLACK,WHITE,GREEN;
}
枚举的好处
将枚举类型用作set或map的类型时,专用且高效。(引自枚举类的介绍)
枚举的典型应用
如 状态码、常量、颜色、类别等
使用规范
- 枚举类名带上Enum后缀,枚举成员名称需要全大写,单词间用下划线隔开。
正例:枚举名字为ProcessStatusEnum的成员名称:SUCCESS / UNKNOWN_REASON - 所有的枚举类型字段必须要有注释,说明每个数据项的用途
引自阿里巴巴开发手册
枚举的本质
枚举类的声明
package java.lang;
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
...
}
下面我们新建一个枚举类`ColorEnum``
public enum ColorEnum{
BLACK,WHITE,GREEN;
}
- 执行
javac ColorEnum.java
命令,生成ColorEnum.class
文件. - 接着执行
javap ColorEnum.class
命令,输入如下内容:
public final class com.sun.advanced.learnenum.ColorEnum extends java.lang.Enum<com.sun.advanced.learnenum.ColorEnum> {
public static final com.sun.advanced.learnenum.ColorEnum BLACK;
public static final com.sun.advanced.learnenum.ColorEnum WHITE;
public static final com.sun.advanced.learnenum.ColorEnum GREEN;
public static com.sun.advanced.learnenum.ColorEnum[] values();
public static com.sun.advanced.learnenum.ColorEnum valueOf(java.lang.String);
static {};
}
从上面可以看出,枚举的本质是
java.lang.Enum
的子类。
尽管enum
看起来很像一种新的数据类型,但实际上,enum是一种受限制的类,并且有自己的方法。
枚举类被修饰为final
,所以不能被其他类所继承。
定义的枚举值被修饰为static final
,本质上枚举值就是一种静态常量枚举其实就是特殊的类,域成员均为常量,且构造方法被默认强制是私有。–阿里巴巴开发手册
枚举的方法
-
String name()
: 返回此枚举常量的名称 -
int ordinal()
: 此枚举常量的序号(它在枚举声明中的位置,其中初始常量的序数为零)。 -
String toString
: 返回枚举常量名 -
boolean equals(Object other)
: 判断是否为同一个对象 -
Class<E> getDeclaringClass()
: 返回实例所属的 enum 类型 -
static <T extends Enum<T>> T valueOf valueOf(Class<T> enumType String name)
: 返回指定名字、给定类的枚举常量 - int compareTo(E other): 如果枚举常量出现在other之前,则返回用一个负值;如果this==other,则返回0;否则,返回正值。枚举常量的出现次数在enum中给出
可以使用==
来比较enum实例
enum
的基本方法:
public class EnumMethodDemo {
public static void main(String[] args) {
System.out.println("******************Print all color**************");
for (ColorEnum colorEnum : ColorEnum.values()) {
System.out.println(colorEnum + " ordinal " + colorEnum.ordinal());
}
System.out.println("******************Print method**************");
ColorEnum black = ColorEnum.BLACK;
System.out.println("black.name(): " + black.name());
System.out.println("black.getDeclaringClass(): " + black.getDeclaringClass());
System.out.println("black.hashCode(): " + black.hashCode());
System.out.println("black.compareTo(ColorEnum.BLACK): " + black.compareTo(ColorEnum.BLACK));
System.out.println("black.equals(ColorEnum.BLACK): " + black.equals(ColorEnum.BLACK));
System.out.println("black.equals(ColorEnum.WHITE): " + black.equals(ColorEnum.WHITE));
System.out.format("black == ColorEnum.WHITE", black == ColorEnum.WHITE);
}
}
输出
******************Print all color**************
BLACK ordinal 0
WHITE ordinal 1
GREEN ordinal 2
******************Print method**************
black.name(): BLACK
black.getDeclaringClass(): class com.sun.advanced.learnenum.ColorEnum
black.hashCode(): 1956725890
black.compareTo(ColorEnum.BLACK): 0
black.equals(ColorEnum.BLACK): true
black.equals(ColorEnum.WHITE): false
black == ColorEnum.WHITE
Process finished with exit code 0
枚举的特性
基本特性
如果枚举中没有定义方法,也可以在最后一个实例后面加逗号、分号或什么都不加
枚举可以添加方法
枚举值认为从0开始的有序数值。
枚举可以添加普通方法、静态方法、抽象方法、构造方法
Java中不允许使用=
为枚举常量赋值。而是添加方法来间接实现显示赋值。
枚举可以实现接口
public interface INumberEnum {
int getCode();
String getDescription();
}
public enum ErrorCodeEnum implements INumberEnum {
OK(0,"成功"),
ERROR_A(100,"错误A"),
ERROR_B(200,"错误B");
private int code;
private String description;
ErrorCodeEnum(int number, String description) {
this.code = number;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
}
枚举的应用
组织常量
以前,在Java中定义常量都是public static final T A;
这样的形式。有了枚举类,你可以将有关联关系的常量组织起来,使代码更加易读、安全,并且还可以使用枚举提供的方法
状态机
我们经常使用switch语句来写状态机。JDK1.7以后,switch已经支持int、
char、
string、
enum`类型的参数。这几种类型的参数比较起来,使用枚举的switch更具有可读性
public enum StateEnum {
GREEN,
YYELLOW,
RED;
}
public class StateMachineDemo {
public static void main(String[] args) {
System.out.println(getTrafficInstruct(StateEnum.RED));
}
public static String getTrafficInstruct(StateEnum singal){
String instruct = "信号灯故障";
switch (singal){
case RED:
instruct="红灯停";
break;
case GREEN:
instruct="黄灯请注意";
break;
case YYELLOW:
instruct="绿灯行";
break;
default:
break;
}
return instruct;
}
}
输出
红灯停
错误码
枚举常常用于定义程序错误码。下面使一个简单示例
public enum HttpStatusEnum {
OK(200,"成功"),
NOT_FOUND(404,"资源未找到");
private int code;
private String msg;
HttpStatusEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
@Override
public String toString() {
return super.toString();
}
}
public class HttpStateDemo {
public static void main(String[] args) {
for (HttpStatusEnum value : HttpStatusEnum.values()) {
System.out.println(value.getCode() +" "+ value.toString());
}
}
}
组织枚举
可以将类型接近的枚举通过接口或类组织起来来,但是一般用接口的方式进行组织。
原因是:Java接口在编译时会自动为enum类型加上public static
修饰符;Java类编译时会自动为enum
类型加上static修饰符,就是说,在类组织enum
,如果你不给他修饰为public,那么之恶能在本包中进行访问
在一个接口的内部,创建实现该接口的枚举,以此将元素进行分组,可以达到将枚举元素分类组织的目的。举例来说,假设你想用enum来表示不同类别的食物,同时还希望每个enum元素仍然保持Food类型,那么可以这样实现:
public interface Food {
enum Appetizer implements Food{
SALAD,SOUP,SPRING_ROLLS;
}
enum MainCourse implements Food{
LASAGNE,BURRITO,PAD_THAI,
LENTILS,HUMMOUS,VINDALOO;
}
enum Dessert implements Food{
TIRAMISU,GELATO,FRUIT;
}
enum Coffee implements Food{
BLACK_COFFEE,DECAF_COFFEE,ESPRESSO,
LATTE,CAPPUCCINO,TEA,HERB_TEA;
}
}
这些枚举都实现了Food接口,所以可以利用Food对具体实例进行实例化
import static com.sun.advanced.learnenum.Food.*;
public class TypeOfFood {
public static void main(String[] args) {
Food food = Appetizer.SALAD;
food = MainCourse.LASAGNE;
food = Dessert.GELATO;
food = Coffee.BLACK_COFFEE;
}
}
枚举工具类
Java 中提供了两个方便操作enum的工具类EnumSet
,EnumMap
EnumSet
Set
是一种集合,只能向其中添加不重复的对象。当然enum也要求成员都是唯一的,所以enum看起来也具有集合的行为。EnumSet
是枚举类型的高性能Set
实现。它要求放入它的枚举常量必须属于同一枚举类型
主要接口:
- noneOf:创建一个具有指定元素类型的空EnumSet
- allOf:创建一个指定元素类型并包含所有枚举值的EnumSet
- range: 创建一个包括枚举值中指定范围元素的EnumSet
- complenmentsOf:初始化集合包括指定集合的补集
- of:创建一个包括参数中所有元素的EnumSet
- copyOf:创建一个包含参数容器的所有元素的EnumSet
public class EnumSetDemo {
public static void main(String[] args) {
EnumSet<HttpStatusEnum> httpStatusEnums = EnumSet.allOf(HttpStatusEnum.class);
for (HttpStatusEnum value : httpStatusEnums) {
System.out.println(value.name());
}
}
}
EnumMap
EnumMap
是一种特殊的Map,它要求其中的key必须来自一个enum
。由于enum本身的限制,所以EnumMap在内部可由数组实现。因此EnumMap的速度很快,我们可以放心的使用enum实例在EnumMap中进行查找操作。不过我们只能将enum的实例作为key来调用put()方法,其他操作与使用一般的Map差不多。
public class EnumMapDemo {
public static void main(String[] args) {
EnumMap enumMap = new EnumMap(StateEnum.class);
enumMap.put(StateEnum.RED,"红灯");
enumMap.put(StateEnum.GREEN,"绿灯");
enumMap.put(StateEnum.YYELLOW,"黄灯");
for (Object o : enumMap.entrySet()) {
System.out.println(o);
}
}
}
参考资料
- Java编程思想
- 深入理解Java枚举类
- 阿里巴巴开发手册