• 枚举学习


    枚举学习

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

  • 相关阅读:
    2017.4.18下午
    2017.4.18上午
    2017.4.17上午
    2017.4.14下午
    2017.4.14上午
    4.17下午
    4.17上午
    4.13下午
    4.13上午
    4.10上午
  • 原文地址:https://www.cnblogs.com/sv00/p/9763786.html
Copyright © 2020-2023  润新知