介绍
在Java中, 我们通过 static final 来定义常量。例如,我们定义周一到周日这7个常量,可以用7个不同的 int 表示
public class Weekday {
public static final int SUN = 0;
public static final int MON = 1;
public static final int TUE = 2;
public static final int WED = 3;
public static final int THU = 4;
public static final int FRI = 5;
public static final int SAT = 6;
}
使用常量时,可以这么引用
if(day == Weekday.SAT || day == Weekday.SUN) {
// TODO: 周末
}
在 JDK 1.5 之前没有枚举类型,那时候一般用常量来替代。而使用 Java 枚举类型 enum 可以更贴近地表示这种常量。
public enum Weekday {
SUN, MON, TUE, WED, THU, FRI, SAT
}
编译成 class 文件后反编译查看:
// Compiled from "Weekday.java"
public final class EnumTest.Weekday extends java.lang.Enum<EnumTest.Weekday> {
public static final EnumTest.Weekday SUN;
public static final EnumTest.Weekday MON;
public static final EnumTest.Weekday TUE;
public static final EnumTest.Weekday WED;
public static final EnumTest.Weekday THU;
public static final EnumTest.Weekday FRI;
public static final EnumTest.Weekday SAT;
public static EnumTest.Weekday[] values();
public static EnumTest.Weekday valueOf(java.lang.String);
static {};
}
从反编译结果可知:
- 枚举类型的关键字
enum其实只是一个语法糖,编译器最终把它转化为一个final类,因此枚举是不可继承的。 - 枚举类型都继承自
java.lang.Enum类。 - 枚举的每一个取值被编译器传化为了一个个
static final属性。 - 本质上,这就是一个普通类,因此你可以在枚举是添加各种方法,甚至是
main方法。
神奇的 values() 方法
从上面我们可以看出枚举类型被添加了一个静态的 values() 方法,但是 java.lang.Enum 并没有该方法。其实,这个方法是编译器添加的。通过这个方法可以获取到该枚举类型的所有取值。这个方法在需要遍历枚举取值,进行判断筛选的场景非常有用
Enum类常用方法
Java枚举类使用详解
定义枚举
用 enum 关键字加上名称和大括号包含起来的枚举值体即可
- 普通枚举类
public enum Weekday {
SUN, MON, TUE, WED, THU, FRI, SAT;
}
- 添加属性和方法
public enum Weekday {
SUN, MON, TUE, WED, THU, FRI, SAT;
public final static int today = 0;
public static int getDay() {
return 0;
}
}
- 带有构造器的枚举
public enum Weekday {
//通过括号赋值, 必须给定构造器
SUN(0), MON(1), TUE(2), WED(3), THU(4), FRI(5), SAT(6);
public Integer val;
Weekday(int val) {
this.val = val;
}
public static void main(String[] args) {
System.out.println(Weekday.THU.val); // 4
}
}
反编译后
可以发现,每个枚举值都是Weekday类型,SUN(0) <==> new Weekday(0)
同理,枚举值内后括号内可以有多个值,如下
public enum ExamEnum {
A(90,100,"优秀"),
B(70,89,"良"),
C(60,69,"及格"),
D(0,59,"不及格");
//最高分
private int max;
//最低分
private int min;
//评级
private String assess;
public String getAssess(){
return assess;
}
ExamEnum(int min,int max,String assess){
this.max = max;
this.min = min;
this.assess = assess;
}
}
-
嵌套枚举类型
我们可以在类,接口或另一个枚举类型中有一个嵌套的枚举类型声明。
相当于静态内部类
-
实现接口的枚举
- 枚举类可以实现接口,并实现接口中的方法
- 枚举值可以重写枚举类中的方法
使用枚举
在使用 Enum 时候有几个地方需要注意:
- enum 类型不支持
public和protected修饰符的构造方法,因此构造函数一定要是private或包级私有的。也正因为如此,所以枚举对象是无法在程序中通过直接调用其构造方法来初始化的。 - 定义 enum 类型时候,如果是简单类型,那么最后一个枚举值后不用跟任何一个符号;但如果有定制方法,那么最后一个枚举值与后面代码要用分号';'隔开,不能用逗号或空格。
- 由于 enum 类型的值实际上是通过运行期构造出对象来表示的,所以在 cluster 环境下,每个虚拟机都会构造出一个同义的枚举对象。因而在做比较操作时候就需要注意,如果直接通过使用等号 ( ‘ == ’ ) 操作符,这些看似一样的枚举值一定不相等,因为这不是同一个对象实例。
- switch case
Weekday weekday = Weekday.SUN;
switch (weekday) {
case MON:
System.out.println("星期一");
break;
case TUE:
System.out.println("星期二");
break;
case WED:
System.out.println("星期三");
break;
case THU:
System.out.println("星期四");
break;
case FRI:
System.out.println("星期五");
break;
case SAT:
System.out.println("星期六");
break;
default:
System.out.println("星期天");
break;
}
- 遍历
for (Weekday weekday : Weekday.values()) {
System.out.println(weekday);
}
- 下标
Weekday.MON.ordinal() // 1
- 枚举默认实现了 Comparable接口
Weekday.MON.compareTo(Weekday.SAT) // -5
Enum 相关工具类
JDK5.0 中在增加 Enum 类的同时,也增加了两个工具类 EnumSet 和 EnumMap,这两个类都放在 java.util 包中。EnumSet 是一个针对枚举类型的高性能的 Set 接口实现。EnumSet 中装入的所有枚举对象都必须是同一种类型,在其内部,是通过 bit-vector 来实现,也就是通过一个 long 型数。EnumSet 支持在枚举类型的所有值的某个范围中进行迭代。回到上面日期枚举的例子上:
enum WeekDayEnum { Mon, Tue, Wed, Thu, Fri, Sat, Sun }
你能够在每周七天日期中进行迭代,EnumSet 类提供一个静态方法 range 让迭代很容易完成:
for(WeekDayEnum day : EnumSet.range(WeekDayEnum.Mon, WeekDayEnum.Fri)) {
System.out.println(day);
}
打印结果如下:
Mon
Tue
Wed
Thu
Fri
EnumSet 还提供了很多个类型安全的获取子集的 of 方法,使你很容易取得子集:
EnumSet<WeekDayEnum> subset = EnumSet.of(WeekDayEnum.Mon, WeekDayEnum.Wed);
for (WeekDayEnum day : subset) {
System.out.println(day);
}
打印结果如下:
Mon
Wed
与 EnumSet 类似,EnumMap 也是一个高性能的 Map 接口实现,用来管理使用枚举类型作为 keys 的映射表,内部是通过数组方式来实现。EnumMap 将丰富的和安全的 Map 接口与数组快速访问结合到一起,如果你希望要将一个枚举类型映射到一个值,你应该使用 EnumMap。看下面的例子:
// 定义一个 EnumMap 对象,映射表主键是日期枚举类型,值是颜色枚举类型
private static Map<WeekDayEnum, RainbowColor> schema =
new EnumMap<WeekDayEnum, RainbowColor>(WeekDayEnum.class);
static{
// 将一周的每一天与彩虹的某一种色彩映射起来
for (int i = 0; i < WeekDayEnum.values().length; i++) {
schema.put(WeekDayEnum.values()[i], RainbowColor.values()[i]);
}
}
System.out.println("What is the lucky color today?");
System.out.println("It's " + schema.get(WeekDayEnum.Sat));
EnumSet 类的常用方法