Java Enum

java enum(枚举)使用详解 + 总结

Enum、EnumMap、EnumSet的用法讲解

enum 的全称为 enumeration, 是 JDK 1.5 中引入的新特性,存放在 java.lang 包中。

  1. 原始的接口定义常量

  2. 语法(定义)

  3. enum 对象的常用方法介绍

  4. 给 enum 自定义属性和方法

  5. enum 的原理分析

  6. enum 对象常用操作使用

  7. EnumSet,EnumMap 的应用

原始的接口定义常量

1
2
3
4
5
6
7
8
9
public interface IConstants {
String MON = "Mon";
String TUE = "Tue";
String WED = "Wed";
String THU = "Thu";
String FRI = "Fri";
String SAT = "Sat";
String SUN = "Sun";
}

语法(定义)

创建枚举类型要使用 enum 关键字,隐含了所创建的类型都是 java.lang.Enum 类的子类(java.lang.Enum 是一个抽象类)。枚举类型符合通用模式 Class Enum<E extends Enum>,而 E 表示枚举类型的名称。枚举类型的每一个值都将映射到 protected Enum(String name, int ordinal) 构造函数中,在这里,每个值的名称都被转换成一个字符串,并且序数设置表示了此设置被创建的顺序。

1
2
3
public enum EnumTest {
MON, TUE, WED, THU, FRI, SAT, SUN;
}

这段代码实际上调用了7次 Enum(String name, int ordinal):

1
2
3
4
new Enum<EnumTest>("MON",0);
new Enum<EnumTest>("TUE",1);
new Enum<EnumTest>("WED",2);
... ...

enum 对象的常用方法介绍

int compareTo(E o)
比较此枚举对象与指定枚举对象的顺序。枚举默认实现了java.lang.Comparable接口,返回-1,表示此对象在指定枚举对象之前,返回0,表示两者位置相同,返回1,表示此枚举对象在指定枚举对象之后。

Class getDeclaringClass()
返回与此枚举对象的枚举类型相对应的 Class 对象。

String name()
返回此枚举对象的名称,在其枚举声明中对其进行声明。

int ordinal()
返回枚举对象的序数(它在枚举声明中的位置,其中初始常量序数为零)。

String toString()
返回枚举对象的名称,它包含在声明中。

<T extends Enum> T[] values()
values方法在 java.lang.Enum 中并不存在,它是编译器在编译枚举类的时候添加上去的。它返回所有枚举对象的一个数组。

static <T extends Enum> T valueOf(String name)
这个方法同样是编译在编译的时候添加到枚举类中去的。返回带指定名称的枚举对象。

static <T extends Enum> T valueOf(Class enumType, String name)
返回带指定名称的指定枚举类型的枚举常量。

给 enum 自定义属性和方法

如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。而且Java要求必须先定义enum实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
public enum Week {

// 枚举实例定义必须放在最前面
MON("星期一", 1) {
@Override
public boolean isWeekday() {
return true;
}
},

TUE("星期二", 2) {
@Override
public boolean isWeekday() {
return true;
}
},

WED("星期三", 3) {
@Override
public boolean isWeekday() {
return true;
}
},

THU("星期四", 4) {
@Override
public boolean isWeekday() {
return true;
}
},

FRI("星期五", 5) {
@Override
public boolean isWeekday() {
return true;
}
},

SAT("星期六", 6) {
@Override
public boolean isWeekday() {
return true;
}

@Override
public boolean isWeekend() {
return true;
}
},

SUN("星期天", 7) {
@Override
public boolean isWeekday() {
return true;
}

@Override
public boolean isWeekend() {
return true;
}
};

private String name;
private int ordinal;

Week(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}

public String getName() {
return name;
}

public int getOrdinal() {
return ordinal;
}

/**
* 是否是周末
*
* @return
*/
public boolean isWeekend() {
return false;
}

/**
* 是否是工作日
*
* @return
*/
public abstract boolean isWeekday();

/**
* 测试 switch 语句
*
* @param week
* @return
*/
public static Week switchWeek(Week week) {
switch (week) {
case MON:
return Week.MON;
case TUE:
return Week.TUE;
case WED:
return Week.WED;
case THU:
return Week.THU;
case FRI:
return Week.FRI;
case SAT:
return Week.SAT;
case SUN:
return Week.SUN;
default:
return null;
}
}

/**
* 返回匹配自定义属性 name 值的枚举常量
*
* @param name
* @return
*/
public static Week getWeek(String name) {
for (Week week : Week.values()) {
if (week.getName().equals(name)) {
return week;
} else {
continue;
}
}
return null;
}

}
```
给枚举加了 name 和 ordinal 两个字段,并且重载了构造方法。构造方法和其他方法必须放在枚举声明的枚举实例定义的后面。另外,Week.SAT 和 Week.SUN 两个枚举变量后面都加了匿名内部类。

### enum 的原理
每个 enum 类都会集成 java.lang.enum 这个抽象类,而 enum 也是一个抽象类,所以我们可以在 enum 里面定义抽象方法 isWeekday 和 其他非抽象方法。
每个 enum 里面的枚举常量都是 enum 的匿名内部类,所以它可以重写 enum 这个抽象类定义的抽象方法 isWeekday 和其他非抽象的方法。
所以:
```
SUN("星期天", 7) {
@Override
public boolean isWeekend() {
return true;
}
}
```
就相当于:
```
public static final Week SUN = new Week("星期天", 7) {
@Override
public boolean isWeekend() {
return true;
}
}

所以使用普通的 Java 类就可以实现枚举,参考 Java枚举(用Java普通类模拟枚举的实现原理及JDK枚举API使用示例)

enum 对象常用操作使用

compareTo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Week mon = Week.MON;
Week tue = Week.valueOf("TUE");

switch (mon.compareTo(tue)) {
case -1:
System.out.println(mon.getName() + "的位置在" + tue.getName() + "前面");
break;
case 0:
System.out.println(mon.getName() + "的位置与" + tue.getName() + "相同");
break;
case 1:
System.out.println(mon.getName() + "的位置在" + tue.getName() + "后面");
break;

}

输出结果:

1
星期一的位置在星期二前面

values

1
2
3
4
for (Week week : Week.values()) {
System.out.println("name - ordinal : " + week.name() + " - " + week.ordinal());
System.out.println("name - ordinal : " + week.getName() + " - " + week.getOrdinal());
}

输入结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
name - ordinal : MON - 0
name - ordinal : 星期一 - 1
name - ordinal : TUE - 1
name - ordinal : 星期二 - 2
name - ordinal : WED - 2
name - ordinal : 星期三 - 3
name - ordinal : THU - 3
name - ordinal : 星期四 - 4
name - ordinal : FRI - 4
name - ordinal : 星期五 - 5
name - ordinal : SAT - 5
name - ordinal : 星期六 - 6
name - ordinal : SUN - 6
name - ordinal : 星期天 - 7

自定义的属性并不会影响父类 Enum 类里面定义的属性,因为父类中的属性为私有的。

valueOf

1
2
3
4
5
6
7
8
9
Week mon = Week.MON;
Week tue = Week.valueOf("TUE");
Week wed = Week.valueOf(Week.class, "WED");
```
输出结果:
```
mon : MON - 星期一
tue : TUE - 星期二
wed : WED - 星期三

switch 语句

从 java1.6 之后,可以在switch语句的case中放入枚举元素。

1
2
3
4
5
6
7
Week mon = Week.MON;
Week tue = Week.valueOf("TUE");
Week wed = Week.valueOf(Week.class, "WED");

System.out.println(Week.switchWeek(mon).getName());
System.out.println(Week.switchWeek(tue).getName());
System.out.println(Week.switchWeek(wed).getName());

输出结果:

1
2
3
星期一
星期二
星期三

根据自定义的属性返回枚举常量

Week week = Week.getWeek("星期一");
System.out.println(week.name());

输出结果:

MON 

EnumSet,EnumMap 的应用

EnumMap

剖析EnumMap / 计算机程序的思维逻辑

计算机程序的思维逻辑 (51) - 剖析EnumSet

分享到:
Disqus 加载中...

如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理