博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
枚举学习
阅读量:4509 次
发布时间:2019-06-08

本文共 6665 字,大约阅读时间需要 22 分钟。

枚举学习

1. 问题
jdk1.5开始引入了枚举,可以很方便地组织一些固定类型的常量。 看到《Effective Java》这本书中关于枚举那一条建议中有提到“试图使每个常量都从自己的构造器将自身放到map中,会导致编译时错误”,但是这是为什么呢?

2. 写一个枚举类试验下先
public enum StatusEnum {    Initial("initial"),    Done("done")    ;    // 自定义的静态map去存储value和枚举实例的键值对    private static final Map
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, 就会出错:

1317779-20181009235845680-210732071.png

接下来我们用javap反编译其class文件去查看编译后的字节码去探下究竟:

javap -verbose StatusEnum.class

可以看到:

public final class com.sv.lite.StatusEnum extends java.lang.Enum
/* * 常量池省略 */{ 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 "
":(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 "
":(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
;

通过反编译后的代码,不难看出其实我们定义的枚举

  • 枚举是一个类继承自java.lang.Enum<>
  • 定义的每一个枚举项其实是该枚举类中的一个静态域,如:public static final com.sv.lite.StatusEnum Initial

从代码中找到其中的类构造器static块 可以看到先实例化定义的每个静态成员项Initial和Done,然后才是实例化我们定义的静态常量statusEnumMap,所以就解答了前面的问题。

1317779-20181009232200745-1279111966.png
1317779-20181009232940481-277251342.png

3. 结论
在枚举的实例构造器被调用的时候,枚举中定义的静态变量还没有被实例化,因为枚举类会先去实例化我们定义的枚举项(这时需要调用实例构造器)。

作者:SV

出处:https://www.cnblogs.com/sv00
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

转载于:https://www.cnblogs.com/sv00/p/9763786.html

你可能感兴趣的文章
WCF中常用的binding方式
查看>>
AOP 面向切面编程
查看>>
bzoj1012题解
查看>>
[Leetcode] insert interval 插入区间
查看>>
HDU 3874 Necklace(树状数组的离线操作)
查看>>
ansible publishing service
查看>>
php count函数
查看>>
PHP 跨域问题 (转)
查看>>
TFG液晶 字符模块
查看>>
Python2和Python3语法区别
查看>>
SQL Server 触发器
查看>>
Ural 1146 Maximum Sum(DP)
查看>>
《STL源代码分析》---stl_stack.h读书笔记
查看>>
UVA 10385 - Duathlon(三分法)
查看>>
div同时使用两个class
查看>>
在路上,三线城市互联网创业记录
查看>>
spark 编译遇到的错误及解决办法(五)
查看>>
框架篇: React + React-Router + antd + nodejs + express框架开发运用(nodejs做前后端server)...
查看>>
8、使用转换流处理标准输入
查看>>
Git 常用命令
查看>>