简介:关键字 enum 可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用。这是一种非常有用的功能。
1. enum基本特性
创建 enum 时,编译器会为你生成一个相关的类,这个类继承自java.lang.Enum。能够使用它的方法
enum Shrubbery {
GROUND, CRAWLING, HANGING
}
public class EnumClass {
public static void main(String[] args) {
for (Shrubbery shrubbery : Shrubbery.values()) {
System.out.println(shrubbery + " ordinal:" + shrubbery.ordinal());
System.out.println(shrubbery.compareTo(Shrubbery.CRAWLING) + " ");
System.out.println(shrubbery.equals(Shrubbery.CRAWLING) + " ");
System.out.println(shrubbery == Shrubbery.CRAWLING);
System.out.println(shrubbery.getDeclaringClass());
System.out.println(shrubbery.name());
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
}
}
输出结果:
GROUND ordinal:0
-1
false
false
class com.zhihong.Test19.Shrubbery
GROUND
~~~~~~~~~~~~~~~~~~~~~~~~~~
CRAWLING ordinal:1
0
true
true
class com.zhihong.Test19.Shrubbery
CRAWLING
~~~~~~~~~~~~~~~~~~~~~~~~~~
HANGING ordinal:2
1
false
false
class com.zhihong.Test19.Shrubbery
HANGING
~~~~~~~~~~~~~~~~~~~~~~~~~~
- ordinal() 方法返回一个int值(每个 enum 实例声明时的次序,从0开始)。可以用 == 来比较 enum 实例,也可以使用 java.lang.Enum 的 equals(方法。
- 如果在 enum 实例上调用 getDeclaringClass() 方法,我们就可以知道起所属 enum 类。
- 我们可以使用 enum 实例自带 valueof() 或 java.lang.Enum 定义的 static 的 valueof() 方法,根据给定的名称返回相应的 enum 实例。
Shrubbery crawling = Shrubbery.valueOf("CRAWLING");
Shrubbery crawling1 = Enum.valueOf(Shrubbery.class, "CRAWLING");
2. 静态导入enum
package com.zhihong.Test19;
public enum Spiciness {
NOT, MILD, MEDIUM, HOT, FLAMING
}
package com.zhihong.Test;
import static com.zhihong.Test19.Spiciness.*;
public class EnumTest {
public static void main(String[] args) {
System.out.println(MEDIUM);
System.out.println(HOT);
System.out.println(FLAMING);
}
}
静态导入 enum,无需要用 enum 类型修饰其实例,可以直接使用 enum 实例
3. 向 enum 中添加新方法
除了不能继承自一个 enum 之外,我们基本上可以将 enum 看作一个常规的类。也就是说,我们可以向 enum 种添加方法。enum 甚至可以有 main() 方法。
public enum Fruits {
APPLE("苹果"),
BANANA("香蕉"),
PEAR("梨");
private String description;
private Fruits(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public static void main(String[] args) {
for (Fruits fruits : Fruits.values()) {
System.out.println(fruits.name() + ":" + fruits.getDescription());
}
}
}
result:
APPLE:苹果
BANANA:香蕉
PEAR:梨
4. values() 的神秘之处
前面提到,编译器为你创建 enum 类都继承自 Enum 类。然而,如果你研究一下 Enum 类就会发现,它并没有values() 方法。我们可以利用 javap 机制来查看其中的究竟。
public enum Spiciness {
MEDIUM, HOT, FLAMING
}
Compiled from "Spiciness.java"
public final class com.zhihong.Test19.Spiciness extends java.lang.Enum<com.zhihong.Test19.Spiciness> {
public static final com.zhihong.Test19.Spiciness NOT;
descriptor: Lcom/zhihong/Test19/Spiciness;
public static final com.zhihong.Test19.Spiciness MILD;
descriptor: Lcom/zhihong/Test19/Spiciness;
public static final com.zhihong.Test19.Spiciness MEDIUM;
descriptor: Lcom/zhihong/Test19/Spiciness;
public static final com.zhihong.Test19.Spiciness HOT;
descriptor: Lcom/zhihong/Test19/Spiciness;
public static final com.zhihong.Test19.Spiciness FLAMING;
descriptor: Lcom/zhihong/Test19/Spiciness;
public static com.zhihong.Test19.Spiciness[] values();
descriptor: ()[Lcom/zhihong/Test19/Spiciness;
Code:
0: getstatic #1 // Field $VALUES:[Lcom/zhihong/Test19/Spiciness;
3: invokevirtual #2 // Method "[Lcom/zhihong/Test19/Spiciness;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[Lcom/zhihong/Test19/Spiciness;"
9: areturn
LineNumberTable:
line 3: 0
public static com.zhihong.Test19.Spiciness valueOf(java.lang.String);
descriptor: (Ljava/lang/String;)Lcom/zhihong/Test19/Spiciness;
Code:
0: ldc #4 // class com/zhihong/Test19/Spiciness
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class com/zhihong/Test19/Spiciness
9: areturn
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 name Ljava/lang/String;
static {};
descriptor: ()V
Code:
0: new #4 // class com/zhihong/Test19/Spiciness
3: dup
4: ldc #7 // String NOT
6: iconst_0
7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #9 // Field NOT:Lcom/zhihong/Test19/Spiciness;
13: new #4 // class com/zhihong/Test19/Spiciness
16: dup
17: ldc #10 // String MILD
19: iconst_1
20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #11 // Field MILD:Lcom/zhihong/Test19/Spiciness;
26: new #4 // class com/zhihong/Test19/Spiciness
29: dup
30: ldc #12 // String MEDIUM
32: iconst_2
33: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
36: putstatic #13 // Field MEDIUM:Lcom/zhihong/Test19/Spiciness;
39: new #4 // class com/zhihong/Test19/Spiciness
42: dup
43: ldc #14 // String HOT
45: iconst_3
46: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
49: putstatic #15 // Field HOT:Lcom/zhihong/Test19/Spiciness;
52: new #4 // class com/zhihong/Test19/Spiciness
55: dup
56: ldc #16 // String FLAMING
58: iconst_4
59: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
62: putstatic #17 // Field FLAMING:Lcom/zhihong/Test19/Spiciness;
65: iconst_5
66: anewarray #4 // class com/zhihong/Test19/Spiciness
69: dup
70: iconst_0
71: getstatic #9 // Field NOT:Lcom/zhihong/Test19/Spiciness;
74: aastore
75: dup
76: iconst_1
77: getstatic #11 // Field MILD:Lcom/zhihong/Test19/Spiciness;
80: aastore
81: dup
82: iconst_2
83: getstatic #13 // Field MEDIUM:Lcom/zhihong/Test19/Spiciness;
86: aastore
87: dup
88: iconst_3
89: getstatic #15 // Field HOT:Lcom/zhihong/Test19/Spiciness;
92: aastore
93: dup
94: iconst_4
95: getstatic #17 // Field FLAMING:Lcom/zhihong/Test19/Spiciness;
98: aastore
99: putstatic #1 // Field $VALUES:[Lcom/zhihong/Test19/Spiciness;
102: return
LineNumberTable:
line 4: 0
line 3: 65
}
答案是,values() 是由编译器添加的 static 方法。可以看出编译器还为其添加了 valueOf() 方法。
5. 常量相关的方法
Java 的 enum 有一个非常有趣的特性,即它允许程序员为 enum 实例编写方法,从而为每个 enum 实例赋予各自不同的行为。
public enum ConstantSpecificMethod {
DATE_TIME {
public String getInfo() {
return "date time";
}
},
CLASSPATH {
public String getInfo() {
return "classpath";
}
};
public abstract String getInfo();
public static void main(String[] args) throws IOException {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
for (ConstantSpecificMethod value : values()) {
System.out.println(value.getInfo());
System.out.println(value.getClass().getName());
}
}
}
result:
date time
com.zhihong.Test19.ConstantSpecificMethod$1
classpath
com.zhihong.Test19.ConstantSpecificMethod$2
可以看出每个 enum 实例的 class 都不一样了,各自重写了 abstract String getInfo()方法。