前言
在本文中,我们将看到什么是 Java 枚举类,以及它的使用场景和注意事项。
版本约定
- JDK 版本:1.8.0_231
 - Java SE API Documentation:https://docs.oracle.com/javase/8/docs/api/
正文
 
Java 枚举是一个特殊的类,一般表示一组常量,比如一年的 4 个季节,一个年的 12 个月份,一个星期的 7 天,方向有东南西北等。
Java 枚举类使用 enum 关键字来定义,各个常量使用逗号分割。比如,定义个星期的枚举类:
public enum Weekday {SUN, MON, TUE, WED, THU, FRI, SAT;}
枚举类通常用来定义常量,可以将有关联关系的常量组织起来,使代码更加易读、安全,并且还可以使用枚举提供的方法。
枚举的比较
使用 enum 定义的枚举类是一种引用类型。前面我们讲过,引用类型比较,要使用 equals() 方法,如果使用 == 比较,它比较的是两个引用类型的变量是否指向同一个对象。因此,引用类型比较,要使用 equals() 方法,但 enum 类型可以例外。
这是因为 enum 类型的每个常量在 JVM 中只有一个唯一实例,所以可以直接用 == 比较:
if (day == Weekday.FRI) { // ok!}
枚举的本质
通过 enum 定义的枚举类,和其他的 class 有什么区别?
答案是没有任何区别。enum 定义的类型就是 class,只不过它有以下几个特点:
- 定义的 enum 类型总是继承自 java.lang.Enum,且无法被继承;
 - 只能定义出 enum 的实例,而无法通过 new 操作符创建 enum 的实例;
 - 定义的每个实例都是引用类型的唯一实例;
 - 可以将 enum 类型用于 switch 语句。
 
例如,我们定义的 Weekday 枚举类:
public enum Weekday {SUN, MON, TUE, WED, THU, FRI, SAT;}
编译器编译出的 class 大概就像这样:
// 继承自 Enum,标记为 final classpublic final class Weekday extends Enum{public static Weekday[] values(){return (Weekday[])$VALUES.clone();}public static Weekday valueOf(String name){return (Weekday)Enum.valueOf(test12/Weekday, name);}// private 构造方法,确保外部无法调用 new 操作符:private Weekday(String s, int i){super(s, i);}// 每个实例均为全局唯一:public static final Weekday SUN;public static final Weekday MON;public static final Weekday TUE;public static final Weekday WED;public static final Weekday THU;public static final Weekday FRI;public static final Weekday SAT;private static final Weekday $VALUES[];static{SUN = new Weekday("SUN", 0);MON = new Weekday("MON", 1);TUE = new Weekday("TUE", 2);WED = new Weekday("WED", 3);THU = new Weekday("THU", 4);FRI = new Weekday("FRI", 5);SAT = new Weekday("SAT", 6);$VALUES = (new Weekday[] {SUN, MON, TUE, WED, THU, FRI, SAT});}}
所以,编译后的 enum 类和普通 class 并没有任何区别。但是我们自己无法按定义普通 class 那样来定义 enum,必须使用 enum 关键字,这是 Java 语法规定的。
枚举的方法
根据编译后的源码,我们知道 enum 类型总是继承自 java.lang.Enum,它提供了一些基本方法:
values():返回 enum 实例的数组,而且该数组中的元素严格保持在 enum 中声明时的顺序;valueOf():返回带指定名称的指定枚举类型的枚举常量;name():返回实例名;ordinal():返回实例声明时的次序,从 0 开始;getDeclaringClass():返回实例所属的 enum 类型;equals():判断是否为同一个对象。
此外,java.lang.Enum 实现了 Comparable 和 Serializable 接口,所以也提供 compareTo() 方法。
自定义属性和方法
我们在使用枚举的时候不会只定义枚举实例名,还会定义一些属性和方法,方便我们使用。
枚举可以添加普通方法、静态方法、抽象方法、构造方法,枚举也可以实现接口,但是,枚举不能继承。
比如上面的 Weekday 枚举,我们可以添加如下属性和方法:
public enum Weekday {SUN(0, "Sunday"),MON(1, "Monday"),TUE(2, "Tuesday"),WED(3, "Wednesday"),THU(4, "Thursday"),FRI(5, "Friday"),SAT(6, "Saturday");private final int index;private final String name;private Weekday(int index, String name) {this.index = index;this.name = name;}public static String getNameByIndex(int index) {for (Weekday weekday : values()) {if (weekday.getIndex() == index) {return weekday.getName();}}return null;}public int getIndex() {return index;}public String getName() {return name;}}
总结
- Java 使用 enum 定义枚举类型,它被编译器编译为 final class Xxx extends Enum { … };
 - 可以为 enum 编写构造方法、字段和方法;
 enum 的构造方法要声明为 private,字段建议声明为 private final。
转载
- 深入理解 Java 枚举
 
作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/wy3oy3 来源:殷建卫 - 开发笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
