enum再谈

java中枚举声明需用到enum关键字简单的如:

public enum TestEnum {
	Mon,
	Tue,
	Wen,
	Fri
}

 但是我们查看一下编译后得到的汇编就能知道,enum编译后得到的还是一个class,现在用javap -verbose TestEnum命令查看编译得到的class文件:

Classfile /F:/TestEnum.class
  Last modified 2017-5-8; size 868 bytes
  MD5 checksum 485a9071bf44ca9406beceea0dbca950
  Compiled from "TestEnum.java"
public final class TestEnum extends java.lang.Enum<TestEnum>
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
Constant pool:
   #1 = Fieldref           #4.#38         // TestEnum.$VALUES:[LTestEnum;
   #2 = Methodref          #39.#40        // "[LTestEnum;".clone:()Ljava/lang/Object;
   #3 = Class              #23            // "[LTestEnum;"
   #4 = Class              #41            // TestEnum
   #5 = Methodref          #16.#42        // java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
   #6 = Methodref          #16.#43        // java/lang/Enum."<init>":(Ljava/lang/String;I)V
   #7 = String             #17            // Mon
   #8 = Methodref          #4.#43         // TestEnum."<init>":(Ljava/lang/String;I)V
   #9 = Fieldref           #4.#44         // TestEnum.Mon:LTestEnum;
  #10 = String             #19            // Tue
  #11 = Fieldref           #4.#45         // TestEnum.Tue:LTestEnum;
  #12 = String             #20            // Wen
  #13 = Fieldref           #4.#46         // TestEnum.Wen:LTestEnum;
  #14 = String             #21            // Fri
  #15 = Fieldref           #4.#47         // TestEnum.Fri:LTestEnum;
  #16 = Class              #48            // java/lang/Enum
  #17 = Utf8               Mon
  #18 = Utf8               LTestEnum;
  #19 = Utf8               Tue
  #20 = Utf8               Wen
  #21 = Utf8               Fri
  #22 = Utf8               $VALUES
  #23 = Utf8               [LTestEnum;
  #24 = Utf8               values
  #25 = Utf8               ()[LTestEnum;
  #26 = Utf8               Code
  #27 = Utf8               LineNumberTable
  #28 = Utf8               valueOf
  #29 = Utf8               (Ljava/lang/String;)LTestEnum;
  #30 = Utf8               <init>
  #31 = Utf8               (Ljava/lang/String;I)V
  #32 = Utf8               Signature
  #33 = Utf8               ()V
  #34 = Utf8               <clinit>
  #35 = Utf8               Ljava/lang/Enum<LTestEnum;>;
  #36 = Utf8               SourceFile
  #37 = Utf8               TestEnum.java
  #38 = NameAndType        #22:#23        // $VALUES:[LTestEnum;
  #39 = Class              #23            // "[LTestEnum;"
  #40 = NameAndType        #49:#50        // clone:()Ljava/lang/Object;
  #41 = Utf8               TestEnum
  #42 = NameAndType        #28:#51        // valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
  #43 = NameAndType        #30:#31        // "<init>":(Ljava/lang/String;I)V
  #44 = NameAndType        #17:#18        // Mon:LTestEnum;
  #45 = NameAndType        #19:#18        // Tue:LTestEnum;
  #46 = NameAndType        #20:#18        // Wen:LTestEnum;
  #47 = NameAndType        #21:#18        // Fri:LTestEnum;
  #48 = Utf8               java/lang/Enum
  #49 = Utf8               clone
  #50 = Utf8               ()Ljava/lang/Object;
  #51 = Utf8               (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
{
  public static final TestEnum Mon;
    descriptor: LTestEnum;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM

  public static final TestEnum Tue;
    descriptor: LTestEnum;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM

  public static final TestEnum Wen;
    descriptor: LTestEnum;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM

  public static final TestEnum Fri;
    descriptor: LTestEnum;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM

  private static final TestEnum[] $VALUES;
    descriptor: [LTestEnum;
    flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC

  public static TestEnum[] values();
    descriptor: ()[LTestEnum;
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: getstatic     #1                  // Field $VALUES:[LTestEnum;
         3: invokevirtual #2                  // Method "[LTestEnum;".clone:()Ljava/lang/Object;
         6: checkcast     #3                  // class "[LTestEnum;"
         9: areturn
      LineNumberTable:
        line 1: 0

  public static TestEnum valueOf(java.lang.String);
    descriptor: (Ljava/lang/String;)LTestEnum;
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: ldc           #4                  // class TestEnum
         2: aload_0
         3: invokestatic  #5                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
         6: checkcast     #4                  // class TestEnum
         9: areturn
      LineNumberTable:
        line 1: 0

  private TestEnum();
    descriptor: (Ljava/lang/String;I)V
    flags: ACC_PRIVATE
    Code:
      stack=3, locals=3, args_size=3
         0: aload_0
         1: aload_1
         2: iload_2
         3: invokespecial #6                  // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
         6: return
      LineNumberTable:
        line 1: 0
    Signature: #33                          // ()V

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=4, locals=0, args_size=0
         0: new           #4                  // class TestEnum
         3: dup
         4: ldc           #7                  // String Mon
         6: iconst_0
         7: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
        10: putstatic     #9                  // Field Mon:LTestEnum;
        13: new           #4                  // class TestEnum
        16: dup
        17: ldc           #10                 // String Tue
        19: iconst_1
        20: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
        23: putstatic     #11                 // Field Tue:LTestEnum;
        26: new           #4                  // class TestEnum
        29: dup
        30: ldc           #12                 // String Wen
        32: iconst_2
        33: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
        36: putstatic     #13                 // Field Wen:LTestEnum;
        39: new           #4                  // class TestEnum
        42: dup
        43: ldc           #14                 // String Fri
        45: iconst_3
        46: invokespecial #8                  // Method "<init>":(Ljava/lang/String;I)V
        49: putstatic     #15                 // Field Fri:LTestEnum;
        52: iconst_4
        53: anewarray     #4                  // class TestEnum
        56: dup
        57: iconst_0
        58: getstatic     #9                  // Field Mon:LTestEnum;
        61: aastore
        62: dup
        63: iconst_1
        64: getstatic     #11                 // Field Tue:LTestEnum;
        67: aastore
        68: dup
        69: iconst_2
        70: getstatic     #13                 // Field Wen:LTestEnum;
        73: aastore
        74: dup
        75: iconst_3
        76: getstatic     #15                 // Field Fri:LTestEnum;
        79: aastore
        80: putstatic     #1                  // Field $VALUES:[LTestEnum;
        83: return
      LineNumberTable:
        line 2: 0
        line 3: 13
        line 4: 26
        line 5: 39
        line 1: 52
}
Signature: #35                          // Ljava/lang/Enum<LTestEnum;>;
SourceFile: "TestEnum.java"

 现在一点一点解释

1.enum最终编译得到一个继承java.lang.Enum的final class(Enum的源码这里不做讲解,很简单)

2.这个类TestEnum类,有几个类型为自身的静态最终变量Mon、Tue、Wen、Fri也就是在enum中的几个声明,以及一个TestEnum[]数组变量$VALUES

3.静态方法values(),作用是返回该类的静态变量数组$VALUES

4.静态方法valueOf(),内部调用Enum类的方法

 public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                                String name) {
//enumConstantDirectory返回一个第一次使用时懒加载的,简单名称与Enum实例 键值对的map
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
            "No enum constant " + enumType.getCanonicalName() + "." + name);
    }

5.私有构造方法private TestEnum();内部就是调用enum的protected构造方法

6.静态代码块,它的作用是以枚举各个元素对应的String值和从0开始的int值为参数,依次初始化TestEnum对象并赋值给对应的静态最终变量(int值跟enum的ordinal相对应,String值跟enum的name相对应),接下来就是把这些静态变量值放到$VALUES数组中

所有枚举就是含有自身静态变量实例的类

猜你喜欢

转载自xiaoxiaoher.iteye.com/blog/2373200