枚举
此页面由 Daniel Schmid 在 UPL 下贡献什么是枚举?
枚举是所有实例都为编译器已知的类。它们用于创建只能具有少数可能值的类型。
枚举的创建方式类似于类,但使用 enum
关键字而不是 class
。在主体中,有一个枚举常量的实例列表,这些实例由 ,
分隔。枚举的任何实例都不能在枚举常量之外创建。
public enum DayOfWeek {
// enum constant are listed here:
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
所有枚举都隐式扩展 java.lang.Enum
并且不能有任何子类。
访问、评估和比较枚举
枚举的值可以用作常量。为了检查两个枚举实例是否相同,可以使用 ==
运算符。
DayOfWeek weekStart = DayOfWeek.MONDAY;
if (weekStart == DayOfWeek.MONDAY) {
System.out.println("The week starts on Monday.");
}
也可以使用 switch
根据枚举的值执行操作。
DayOfWeek someDay = DayOfWeek.FRIDAY;
switch (someDay) {
case MONDAY ->
System.out.println("The week just started.");
case TUESDAY, WEDNESDAY, THURSDAY ->
System.out.println("We are somewhere in the middle of the week.");
case FRIDAY ->
System.out.println("The weekend is near.");
case SATURDAY, SUNDAY ->
System.out.println("Weekend");
default ->
throw new AssertionError("Should not happen");
}
使用 Switch 表达式,编译器可以检查枚举的所有值是否都已处理。如果 switch 表达式中缺少任何可能的值,则会发生编译错误。这被称为穷举性,也可以通过 密封类 在普通类中实现。
DayOfWeek someDay = DayOfWeek.FRIDAY;
String text = switch (someDay) {
case MONDAY -> "The week just started.";
case TUESDAY, WEDNESDAY, THURSDAY -> "We are somewhere in the middle of the week.";
case FRIDAY -> "The weekend is near.";
case SATURDAY, SUNDAY -> "Weekend";
};
System.out.println(text);
向枚举添加成员
与类一样,枚举也可以有构造函数、方法和字段。为了添加这些,需要在枚举常量列表之后添加一个 ;
。构造函数的参数在枚举常量声明后的括号中传递。
public enum DayOfWeek {
MONDAY("MON"), TUESDAY("TUE"), WEDNESDAY("WED"), THURSDAY("THU"), FRIDAY("FRI"), SATURDAY("SAT"), SUNDAY("SUN");
private final String abbreviation;
DayOfWeek(String abbreviation) {
this.abbreviation = abbreviation;
}
public String getAbbreviation() {
return abbreviation;
}
}
特殊方法
所有枚举都有一些隐式添加的方法。
例如,name()
方法存在于所有枚举实例中,可用于获取枚举常量的名称。类似地,名为 ordinal()
的方法返回枚举常量在声明中的位置。
System.out.println(DayOfWeek.MONDAY.name()); // prints "MONDAY"
System.out.println(DayOfWeek.MONDAY.ordinal()); // prints "0" because MONDAY is the first constant in the DayOfWeek enum
除了实例方法之外,还向所有枚举添加了静态方法。values()
方法返回一个包含枚举所有实例的数组,valueOf(String)
方法可用于通过其名称获取特定实例。
DayOfWeek[] days = DayOfWeek.values(); // all days of the week
DayOfWeek monday = DayOfWeek.valueOf("MONDAY");
此外,枚举实现了 Comparable
接口。默认情况下,枚举按其序数排序,即按枚举常量出现的顺序排序。这允许比较枚举实例以及排序或搜索。
public void compareDayOfWeek(DayOfWeek dayOfWeek){
int comparison = dayOfWeek.compareTo(DayOfWeek.WEDNESDAY);
if ( comparison < 0) {
System.out.println("It's before the middle of the work week.");
} else if(comparison > 0){
System.out.println("It's after the middle of the work week.");
} else {
System.out.println("It's the middle of the work week.");
}
}
List<DayOfWeek> days = new ArrayList<>(List.of(DayOfWeek.FRIDAY, DayOfWeek.TUESDAY, DayOfWeek.SATURDAY));
Collections.sort(days);
使用枚举作为单例
由于枚举只能具有特定数量的实例,因此可以通过创建一个只有一个枚举常量的枚举来创建单例。
public enum SomeSingleton {
INSTANCE;
//fields, methods, etc.
}
枚举中的抽象方法
即使枚举不能扩展,它们仍然可以具有 abstract
方法。在这种情况下,每个枚举常量中都必须存在一个实现。
enum MyEnum {
A() {
@Override
void doSomething() {
System.out.println("a");
}
},
B() {
@Override
void doSomething() {
System.out.println("b");
}
};
abstract void doSomething();
}
注意事项
在使用实例数量(或名称)可能发生变化的枚举时,应谨慎。每当枚举常量发生更改时,其他期望枚举旧版本的代码可能无法按预期工作。这可能表现为编译错误(例如,当引用已删除的枚举常量时)、运行时错误(例如,如果存在 default
案例,即使新的枚举常量应该单独处理)或其他不一致(例如,如果枚举的值已保存到文件,然后读取并期望该值仍然存在)。
更改枚举常量时,建议查看所有使用该枚举的代码。这在枚举也被其他人代码使用的情况下尤其重要。
此外,在存在大量实例的情况下,可能值得考虑使用其他选项,因为在代码中的单个位置列出大量实例可能不灵活。例如,在这种情况下,最好使用配置文件来列出所有实例,并在程序中读取这些配置文件。
结论
枚举提供了一种简单安全的方式来表示一组固定的常量,同时保留了类的大部分灵活性。它们是一种特殊的类,可用于编写优雅、可读且可维护的代码,并且与其他较新的现代功能(如 Switch 表达式)配合良好。另一种特殊的类是 Java 19 中引入的 Record 类。访问我们的 Records 教程 以了解更多信息。
要了解有关枚举的更多信息,请访问 java.lang.Enum
javadoc。
上次更新: 2023 年 10 月 2 日