枚举学习
1. 问题
jdk1.5开始引入了枚举,可以很方便地组织一些固定类型的常量。
看到《Effective Java》这本书中关于枚举那一条建议中有提到,但是这是为什么呢?
2. 写一个枚举类试验下先
public enum StatusEnum {
Initial("initial"),
Done("done")
;
// 自定义的静态map去存储value和枚举实例的键值对
private static final Map<String, StatusEnum> statusEnumMap = Maps.newHashMap();
static {
// 静态构造函数中将枚举实例填充到statusEnumMap中
for (StatusEnum statusEnum : values()) {
statusEnumMap.put(statusEnum.value, statusEnum);
}
}
private String value;
StatusEnum(String value) {
this.value = value;
// statusEnumMap.put(value, this);
}
/**
* 通过value的字符串值获取枚举实例项
* @param value
* @return
*/
public static StatusEnum fromString(String value) {
return statusEnumMap.get(value);
}
}
如果试图在构造器中引用这个statusEnumMap
, 就会出错:
接下来我们用javap反编译其class文件去查看编译后的字节码去探下究竟:
javap -verbose StatusEnum.class
可以看到:
public final class com.sv.lite.StatusEnum extends java.lang.Enum<com.sv.lite.StatusEnum>
/*
* 常量池省略
*/
{
public static final com.sv.lite.StatusEnum Initial;
descriptor: Lcom/sv/lite/StatusEnum;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static final com.sv.lite.StatusEnum Done;
descriptor: Lcom/sv/lite/StatusEnum;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static com.sv.lite.StatusEnum[] values();
descriptor: ()[Lcom/sv/lite/StatusEnum;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: getstatic #1 // Field $VALUES:[Lcom/sv/lite/StatusEnum;
3: invokevirtual #2 // Method "[Lcom/sv/lite/StatusEnum;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[Lcom/sv/lite/StatusEnum;"
9: areturn
LineNumberTable:
line 7: 0
public static com.sv.lite.StatusEnum valueOf(java.lang.String);
descriptor: (Ljava/lang/String;)Lcom/sv/lite/StatusEnum;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: ldc #4 // class com/sv/lite/StatusEnum
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/sv/lite/StatusEnum
9: areturn
LineNumberTable:
line 7: 0
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 name Ljava/lang/String;
public static com.sv.lite.StatusEnum fromString(java.lang.String);
descriptor: (Ljava/lang/String;)Lcom/sv/lite/StatusEnum;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #8 // Field statusEnumMap:Ljava/util/Map;
3: aload_0
4: invokeinterface #9, 2 // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
9: checkcast #4 // class com/sv/lite/StatusEnum
12: areturn
LineNumberTable:
line 26: 0
LocalVariableTable:
Start Length Slot Name Signature
0 13 0 value Ljava/lang/String;
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=5, locals=4, args_size=0
0: new #4 // class com/sv/lite/StatusEnum
3: dup
4: ldc #10 // String Initial
6: iconst_0
7: ldc #11 // String initial
9: invokespecial #12 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
12: putstatic #13 // Field Initial:Lcom/sv/lite/StatusEnum;
15: new #4 // class com/sv/lite/StatusEnum
18: dup
19: ldc #14 // String Done
21: iconst_1
22: ldc #15 // String done
24: invokespecial #12 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
27: putstatic #16 // Field Done:Lcom/sv/lite/StatusEnum;
30: iconst_2
31: anewarray #4 // class com/sv/lite/StatusEnum
34: dup
35: iconst_0
36: getstatic #13 // Field Initial:Lcom/sv/lite/StatusEnum;
39: aastore
40: dup
41: iconst_1
42: getstatic #16 // Field Done:Lcom/sv/lite/StatusEnum;
45: aastore
46: putstatic #1 // Field $VALUES:[Lcom/sv/lite/StatusEnum;
49: invokestatic #17 // Method com/google/common/collect/Maps.newHashMap:()Ljava/util/HashMap;
52: putstatic #8 // Field statusEnumMap:Ljava/util/Map;
55: invokestatic #18 // Method values:()[Lcom/sv/lite/StatusEnum;
58: astore_0
59: aload_0
60: arraylength
61: istore_1
62: iconst_0
63: istore_2
64: iload_2
65: iload_1
66: if_icmpge 93
69: aload_0
70: iload_2
71: aaload
72: astore_3
73: getstatic #8 // Field statusEnumMap:Ljava/util/Map;
76: aload_3
77: getfield #7 // Field value:Ljava/lang/String;
80: aload_3
81: invokeinterface #19, 3 // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
86: pop
87: iinc 2, 1
90: goto 64
93: return
LineNumberTable:
line 8: 0
line 9: 15
line 7: 30
line 12: 49
line 14: 55
line 15: 73
line 14: 87
line 17: 93
LocalVariableTable:
Start Length Slot Name Signature
73 14 3 statusEnum Lcom/sv/lite/StatusEnum;
StackMapTable: number_of_entries = 2
frame_type = 254 /* append */
offset_delta = 64
locals = [ class "[Lcom/sv/lite/StatusEnum;", int, int ]
frame_type = 248 /* chop */
offset_delta = 28
}
Signature: #49 // Ljava/lang/Enum<Lcom/sv/lite/StatusEnum;>;
通过反编译后的代码,不难看出其实我们定义的枚举
从代码中找到其中的类构造器static块
可以看到先实例化定义的每个静态成员项Initial和Done
,然后才是实例化我们定义的静态常量statusEnumMap
,所以就解答了前面的问题。
3. 结论
在枚举的实例构造器被调用的时候,枚举中定义的静态变量还没有被实例化,因为枚举类会先去实例化我们定义的枚举项(这时需要调用实例构造器)。
作者:SV
出处:https://www.cnblogs.com/sv00
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。