码迷,mamicode.com
首页 > 其他好文 > 详细

枚举学习

时间:2018-10-10 01:04:06      阅读:187      评论:0      收藏:0      [点我收藏+]

标签:class   pen   ast   常量池   枚举   let   引用   枚举类   tac   

枚举学习

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
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

枚举学习

标签:class   pen   ast   常量池   枚举   let   引用   枚举类   tac   

原文地址:https://www.cnblogs.com/sv00/p/9763786.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!