前言
在本文中,我们将看到什么是 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 class
public 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 来源:殷建卫 - 开发笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。