通过字节码深入分析java的枚举类型enum

 1.      Java中的枚举究竟是什么鬼?

如果从C++转java的话,会发现一个现象那就是在java中的枚举跟C++区别非常大,甚至可以说除了名字一样外,其他实现等都是非常不同的,在C++枚举更像个常数,而java的枚举更靠近正常的普通成员内部类。让我们从字节码角度看看java中的enum究竟是什么东西吧

源码:

    public enum book{

        BOOK1,BOOK2,BOOK3

}

字节码:

  Last modified 2017-7-23; size 1026 bytes

  MD5 checksum 338ca8c3927b424ae7b0acacb42fd28b

  Compiled from "ChildTest.java"

public final class ChildTest$book extendsjava.lang.Enum

  minor version: 0

  major version: 52

  flags:ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM

Constantpool:

   #1 = Class              #2             // ChildTest$book

   #2 = Utf8              ChildTest$book

   #3 = Class              #4             // java/lang/Enum

   #4 = Utf8               java/lang/Enum

   #5 = Utf8               BOOK1

   #6 = Utf8               LChildTest$book;

   #7 = Utf8               BOOK2

   #8 = Utf8               BOOK3

   #9 = Utf8               ENUM$VALUES

  #10 = Utf8               [LChildTest$book;

  #11 = Utf8              

  #12 = Utf8               ()V

  #13 = Utf8               Code

  #14 = String             #5             // BOOK1

  #15 = Methodref          #1.#16         //ChildTest$book."":(Ljava/lang

/String;I)V

  #16 = NameAndType        #17:#18        //"":(Ljava/lang/String;I)V

  #17 = Utf8              

  #18 = Utf8               (Ljava/lang/String;I)V

  #19 = Fieldref           #1.#20         // ChildTest$book.BOOK1:LChildTest$boo

k;

  #20 = NameAndType        #5:#6          // BOOK1:LChildTest$book;

  #21 = String             #7             // BOOK2

  #22 = Fieldref           #1.#23         // ChildTest$book.BOOK2:LChildTest$boo

k;

  #23 = NameAndType        #7:#6          // BOOK2:LChildTest$book;

  #24 = String             #8             // BOOK3

  #25 = Fieldref           #1.#26         // ChildTest$book.BOOK3:LChildTest$boo

k;

  #26 = NameAndType        #8:#6          // BOOK3:LChildTest$book;

  #27 = Fieldref           #1.#28         // ChildTest$book.ENUM$VALUES:[LChildT

est$book;

  #28 = NameAndType        #9:#10         // ENUM$VALUES:[LChildTest$book;

  #29 = Utf8               LineNumberTable

  #30 =Utf8               LocalVariableTable

  #31 = Methodref          #3.#16         //java/lang/Enum."":(Ljava/lang

/String;I)V

  #32 = Utf8               this

  #33 = Utf8               values

  #34 = Utf8               ()[LChildTest$book;

  #35 = Methodref          #36.#38        // java/lang/System.arraycopy:(Ljava/l

ang/Object;ILjava/lang/Object;II)V

  #36 = Class              #37            // java/lang/System

  #37 = Utf8               java/lang/System

  #38 = NameAndType        #39:#40        // arraycopy:(Ljava/lang/Object;ILjava

/lang/Object;II)V

  #39 = Utf8               arraycopy

  #40 = Utf8              (Ljava/lang/Object;ILjava/lang/Object;II)V

  #41 = Utf8               valueOf

  #42 = Utf8              (Ljava/lang/String;)LChildTest$book;

  #43 = Methodref          #3.#44         // java/lang/Enum.valueOf:(Ljava/lang/

Class;Ljava/lang/String;)Ljava/lang/Enum;

  #44 = NameAndType        #41:#45        // valueOf:(Ljava/lang/Class;Ljava/lan

g/String;)Ljava/lang/Enum;

  #45 = Utf8              (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;

 

  #46 = Utf8               SourceFile

  #47 = Utf8               ChildTest.java

  #48 = Utf8               Signature

  #49 = Utf8               Ljava/lang/Enum;

  #50 = Utf8               InnerClasses

  #51 = Class              #52            // ChildTest

  #52 = Utf8               ChildTest

  #53 = Utf8               book

{

  public static final ChildTest$book BOOK1;

    descriptor: LChildTest$book;

    flags: ACC_PUBLIC,ACC_STATIC, ACC_FINAL, ACC_ENUM

 

  public static finalChildTest$book BOOK2;

    descriptor:LChildTest$book;

    flags: ACC_PUBLIC,ACC_STATIC, ACC_FINAL, ACC_ENUM

 

  public static finalChildTest$book BOOK3;

    descriptor:LChildTest$book;

    flags: ACC_PUBLIC,ACC_STATIC, ACC_FINAL, ACC_ENUM

 

  private static finalChildTest$book[] ENUM$VALUES;

    descriptor:[LChildTest$book;

    flags: ACC_PRIVATE,ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC

 

  static {};

    descriptor: ()V

    flags:ACC_STATIC

    Code:

      stack=4,locals=0, args_size=0

         0:new           #1                  // class ChildTest$book

         3: dup

         4:ldc           #14                 // String BOOK1

         6: iconst_0

         7:invokespecial #15                 //Method "":(Ljava/lang/Str

ing;I)V

        10:putstatic     #19                 // FieldBOOK1:LChildTest$book;

        13:new           #1                  // class ChildTest$book

        16: dup

        17:ldc           #21                 // String BOOK2

        19:iconst_1

        20:invokespecial #15                 //Method "":(Ljava/lang/Str

ing;I)V

        23:putstatic     #22                 // Field BOOK2:LChildTest$book;

        26:new           #1                  // class ChildTest$book

        29: dup

        30:ldc           #24                 // String BOOK3

        32:iconst_2

        33:invokespecial #15                 //Method "":(Ljava/lang/Str

ing;I)V

        36:putstatic     #25                 // FieldBOOK3:LChildTest$book;

        39:iconst_3

        40:anewarray     #1                  // class ChildTest$book

        43: dup

        44:iconst_0

        45:getstatic     #19                 // FieldBOOK1:LChildTest$book;

        48: aastore

        49: dup

        50:iconst_1

        51:getstatic     #22                 // FieldBOOK2:LChildTest$book;

        54: aastore

        55: dup

        56: iconst_2

        57:getstatic     #25                 // FieldBOOK3:LChildTest$book;

        60: aastore

        61:putstatic     #27                 // FieldENUM$VALUES:[LChildTest$b

ook;

        64: return

      LineNumberTable:

        line 20: 0

        line 19: 39

      LocalVariableTable:

        Start Length  Slot  Name  Signature

 

  privateChildTest$book(java.lang.String, int);

    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 #31                 //Method java/lang/Enum."":

(Ljava/lang/String;I)V

         6: return

      LineNumberTable:

        line 19: 0

      LocalVariableTable:

        Start Length  Slot  Name  Signature

            0       7    0  this   LChildTest$book;

 

  public static ChildTest$book[] values();

    descriptor: ()[LChildTest$book;

    flags: ACC_PUBLIC, ACC_STATIC

    Code:

      stack=5, locals=3, args_size=0

        0: getstatic     #27                 // FieldENUM$VALUES:[LChildTest$b

ook;

         3: dup

         4: astore_0

         5: iconst_0

         6: aload_0

         7: arraylength

         8: dup

         9: istore_1

        10: anewarray     #1                 // classChildTest$book

        13: dup

        14: astore_2

        15: iconst_0

        16: iload_1

        17: invokestatic  #35                 // Methodjava/lang/System.arrayco

py:(Ljava/lang/Object;ILjava/lang/Object;II)V

        20: aload_2

        21: areturn

      LineNumberTable:

        line 1: 0

      LocalVariableTable:

        Start Length  Slot  Name  Signature

 

  public static ChildTest$bookvalueOf(java.lang.String);

    descriptor: (Ljava/lang/String;)LChildTest$book;

    flags: ACC_PUBLIC, ACC_STATIC

    Code:

      stack=2, locals=1, args_size=1

         0: ldc           #1                  // class ChildTest$book

         2: aload_0

         3: invokestatic  #43                 // Method java/lang/Enum.valueOf:(

Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;

         6: checkcast     #1                  // class ChildTest$book

         9: areturn

      LineNumberTable:

        line 1: 0

      LocalVariableTable:

        Start Length  Slot  Name  Signature

}

SourceFile:"ChildTest.java"

Signature:#49                          //Ljava/lang/Enum;

InnerClasses:

     public static final #53= #1 of #51;//book=class ChildTest$book of class Ch

ildTest

--你会发现,编译器会替我们生成一个ChildTest$book.class文件,字节码如上文,很明显,跟普通的内部类一样。

(1)从深红色部分可以看出book这个枚举类型本质上是一个继承了一个Enum的类。

(2)从红色部分可以看出,我们在枚举中定义的三个常量实际上就是static final ChildTest$book 类型的常量。而且编译器还帮我们添加了一个常量数组static final ChildTest$book[] ENUM$VALUES。

(3)从绿色部分可以看出,编译器在clinit方法中,调用了构造方法,分别对三个常量进行了初始化

(4)从蓝色部分可以看出,构造方法中调用了父类ENUM的构造方法。并且注意,该构造方法是私有的,也就是说其他类是无法调用的。(包括外部类)

(5)另外编译器还帮我们添加了两个public静态成员方法values()和 valueOf

你可能感兴趣的:(java,Java,枚举,enum)