1 定义
enum全称为enumeration,中文意为枚举,枚举简单的说就是一种数据类型,只不过是这种数据类型只包含自定义的特定数据,它是一组有共同特性的数据的集合。
创建枚举类型是需要用到enum关键字,如:
public enum Color{
RED, GREEN, BLUE, BLACK, PINK, WHITE;
}enum的语法看似与class不同,但它实际上就是一个类,经过编译器编译之后得到一个.class文件
把上面的编译成 Gender.class, 然后用 javap -c Gender反编译出来就是

从字节码知
Gender 是 final 的
Gender 继承自 java.lang.Enum 类
声明了字段对应的两个 static final Gender 的实例
实现了 values() 和 valueOf(String) 静态方法
static{} 对所有成员进行初始化
有了以上的字节码,我们作进一步还原出 Gender 的普通类大概是这样的
public final class Gender extends java.lang.Enum {
public static final Gender Male; public static final Gender Female;
private static final Gender[] $VALUES;
static {
Male = new Gender("Male", 0);
Female = new Gender("Female", 1);
$VALUES = new Gender[] {Male, Female};
} //是我加上去的,是为了模拟枚举实例的创建,其实实例都是在 static 块中创建的。
private Gender(String name, int original) { super(name, original)
}
public static Gender[] values() { return $VALUE.clone();
}
public static Gender valueOf(String name) { return Enum.valueOf(Gender.class, name);
}
}创建的枚举类型默认是java.lang.enum<枚举类型名>(抽象类)的子类
每个枚举项的类型都为public static final 。
当然上面的那个类是无法被编译的,因为 Java 编译器限制了我们显式的继承自 java.Lang.Enum 类, 报错 "The type Gender may not subclass Enum explicitly", 虽然 java.Lang.Enum 声明的是

这样看来枚举类其实用了多例模式,枚举类的实例是有范围限制的
它同样像我们的传统常量类,只是它的元素是有限的枚举类本身的实例
它继承自 java.lang.Enum, 所以可以直接调用 java.lang.Enum 的方法,如 name(), original() 等
name 就是常量名称

original 与 C 的枚举一样的编号

因为Java的单继承机制,emum不能再用extends继承其他的类。

可以在枚举类中自定义构造方法,但必须是 private 或 package protected, 因为枚举本质上是不允许在外面用 new Gender() 方式来构造实例的(Cannot instantiate the type Gender)
结合枚举实现接口以及自定义方法,可以写出下面那样的代码

方法可以定义成所有实例公有,也可以让个别元素独有
需要特别注明一下,上面在 Male {} 声明一个 print() 方法后实际产生一个 Gender 的匿名子类,编译后的 Gender$1,反编译它

所以在 emum Gender 那个枚举中的成员 Male 相当于是
public static final Male = new Gender$1("Male", 0); //而不是 new Gender("Male", 0)上面4: Invokespecial #1 要调用到下面的Gender(java.lang.String, int, Gender$1)方法
若要研究完整的 Male 元素的初始化过程就得 javap -c Gender 看 Gender.java 产生的所有字节码,在此列出片断

在 static{} 中大致看下 Male 的初始过程:加载 Gender

1(java.lang.String, int) 构造函数生成一个 Gender$1 实例赋给 Male 属性
既然enum是一个类,那么它就可以像一般的类一样拥有自己的属性与方法。但Java要求必须先定义enum实例。
否则会编译错误。
public enum Color {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
// 普通方法
public static String getName(int index) {
for (Color c : Color.values()) {
if (c.getIndex() == index) {
return c.name;
}
}
return null;
}
// get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}枚举实例的创建过程:枚举类型符合通用模式 Class Enum<E extends Enum<E>>,而 E 表示枚举类型的名称。枚举类型的每一个值都将映射到 protected Enum(String name, int ordinal) 构造函数中,在这里,每个值的名称都被转换成一个字符串,并且序数设置表示了此设置被创建的顺序。
public enum Color{
RED, GREEN, BLUE, BLACK, PINK, WHITE;
}相当于调用了六次Enum<Color>构造方法
Enum<Color>("RED", 0);
Enum<Color>("GREEN", 1);
Enum<Color>("BLUE", 2);
Enum<Color>("BLACK", 3);
Enum<Color>("PINK",4);
Enum<Color>("WHITE", 5);
枚举类型的常用方法:
int compareTo(E o) 比较此枚举与指定对象的顺序。
Class<E> getDeclaringClass() 返回与此枚举常量的枚举类型相对应的 Class 对象。
String name() 返回此枚举常量的名称,在其枚举声明中对其进行声明。
int ordinal() 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零
String toString() 返回枚举常量的名称,它包含在声明中。
static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) 返回带指定名称的指定枚举类型的枚举常量。
二、常用用法
用法一:常量
在JDK1.5 之前,我们定义常量都是: public static fianl.... 。现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。
用法二:switch
JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强。
enum Color{
RED, GREEN, BLUE, BLACK, PINK, WHITE;
}
public class TestEnum {
public void changeColor(){
Color color = Color.RED;
System.out.println("原色:" + color);
switch(color){
case RED:
color = Color.GREEN;
System.out.println("变色:" + color);
break;
case GREEN:
color = Color.BLUE;
System.out.println("变色:" + color);
break;
case BLUE:
color = Color.BLACK;
System.out.println("变色:" + color);
break;
case BLACK:
color = Color.PINK;
System.out.println("变色:" + color);
break;
case PINK:
color = Color.WHITE;
System.out.println("变色:" + color);
break;
case WHITE:
color = Color.RED;
System.out.println("变色:" + color);
break;
}
}
public static void main(String[] args){
TestEnum testEnum = new TestEnum();
testEnum.changeColor();
}
}用法三:实现接口
public interface Behaviour {
void print();
String getInfo();
}
public enum Color implements Behaviour {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
// 接口方法
@Override
public String getInfo() {
return this.name;
}
// 接口方法
@Override
public void print() {
System.out.println(this.index + ":" + this.name);
}
}用法四:枚举集合的应用
java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的 key是enum类型,而value则可以是任意类型。关于这个两个集合的使用就不在这里赘述,可以参考JDK文档
public class Test {
public static void main(String[] args) {
// EnumSet的使用
EnumSet<EnumTest> weekSet = EnumSet.allOf(EnumTest.class);
for (EnumTest day : weekSet) {
System.out.println(day);
}
// EnumMap的使用
EnumMap<EnumTest, String> weekMap = new EnumMap(EnumTest.class);
weekMap.put(EnumTest.MON, "星期一");
weekMap.put(EnumTest.TUE, "星期二");
// ... ...
for (Iterator<Entry<EnumTest, String>> iter = weekMap.entrySet().iterator(); iter.hasNext();) {
Entry<EnumTest, String> entry = iter.next();
System.out.println(entry.getKey().name() + ":" + entry.getValue());
}
}
}三、综合实例
最简单的使用
最简单的枚举类
public enum Weekday {
SUN,MON,TUS,WED,THU,FRI,SAT
}如何使用它呢?
先来看看它有哪些方法:

这是Weekday可以调用的方法和参数。发现它有两个方法:values()和valueOf()。还有我们刚刚定义的七个变量

这些事枚举变量的方法。我们接下来会演示几个比较重要的

这段代码,我们演示了几个常用的方法和功能:
作者:JavaEdge
链接:https://www.jianshu.com/p/4b51ac50d78d
随时随地看视频