Java中Enum类下的values()方法的由来

来源:互联网 发布:云计算就是虚拟化吗 编辑:程序博客网 时间:2024/06/07 11:39

Java中Enum类下的values()方法的由来

参考 think in java 19章,values()的神秘之处

有如下Enum类:

public enum Test{
 A,B,C
}

该类下有values()方法,但查API可知道java.lang.Enum<ElementType>下根本没有这个方法,该方法在java.lang.annotation.ElementType类下(public enum ElementType extends Enum<ElementType>),我们先看看编译后,用javap命令查看编译后的内容:

C:\>javap Test
Compiled from "Test.java"
public final class Test extends java.lang.Enum<<FONT color=#fe3824>Test
> {
  public static final Test A;
  public static final Test B;
  public static final Test C;
  public static Test[] values();
  public static Test valueOf(java.lang.String);
  static {};
}

可以看出,貌似编译后Test是实现了java.lang.annotation.ElementType这个接口,再看其字节码:

 C:\>javap -v Test
Classfile /C:/Test.class
  Last modified 2012-11-22; size 782 bytes
  MD5 checksum 17335f37d5ac9d7fe7d5544782cf7088
  Compiled from "Test.java"
public final class Test extends java.lang.Enum
  Signature: #32                          // Ljava/lang/Enum;
  SourceFile: "Test.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
Constant pool:
   #1 = Fieldref           #4.#35         //  Test.$VALUES:[LTest;
   #2 = Methodref          #36.#37        //  "[LTest;".clone:()Ljava/lang/Objec
t;
   #3 = Class              #20            //  "[LTest;"
   #4 = Class              #38            //  Test
   #5 = Methodref          #14.#39        //  java/lang/Enum.valueOf:(Ljava/lang
/Class;Ljava/lang/String;)Ljava/lang/Enum;
   #6 = Methodref          #14.#40        //  java/lang/Enum."":(Ljava/lan
g/String;I)V
   #7 = String             #15            //  A
   #8 = Methodref          #4.#41         //  Test."":(Ljava/lang/String;I
)V
   #9 = Fieldref           #4.#42         //  Test.A:LTest;
  #10 = String             #17            //  B
  #11 = Fieldref           #4.#43         //  Test.B:LTest;
  #12 = String             #18            //  C
  #13 = Fieldref           #4.#44         //  Test.C:LTest;
  #14 = Class              #45            //  java/lang/Enum
  #15 = Utf8               A
  #16 = Utf8               LTest;
  #17 = Utf8               B
  #18 = Utf8               C
  #19 = Utf8               $VALUES
  #20 = Utf8               [LTest;
  #21 = Utf8               values
  #22 = Utf8               ()[LTest;
  #23 = Utf8               Code
  #24 = Utf8               LineNumberTable
  #25 = Utf8               valueOf
  #26 = Utf8               (Ljava/lang/String;)LTest;
  #27 = Utf8              
  #28 = Utf8               (Ljava/lang/String;I)V
  #29 = Utf8               Signature
  #30 = Utf8               ()V
  #31 = Utf8              
  #32 = Utf8               Ljava/lang/Enum;
  #33 = Utf8               SourceFile
  #34 = Utf8               Test.java
  #35 = NameAndType        #19:#20        //  $VALUES:[LTest;
  #36 = Class              #20            //  "[LTest;"
  #37 = NameAndType        #46:#47        //  clone:()Ljava/lang/Object;
  #38 = Utf8               Test
  #39 = NameAndType        #25:#48        //  valueOf:(Ljava/lang/Class;Ljava/la
ng/String;)Ljava/lang/Enum;
  #40 = NameAndType        #27:#28        //  "":(Ljava/lang/String;I)V
  #41 = NameAndType        #27:#28        //  "":(Ljava/lang/String;I)V
  #42 = NameAndType        #15:#16        //  A:LTest;
  #43 = NameAndType        #17:#16        //  B:LTest;
  #44 = NameAndType        #18:#16        //  C:LTest;
  #45 = Utf8               java/lang/Enum
  #46 = Utf8               clone
  #47 = Utf8               ()Ljava/lang/Object;
  #48 = Utf8               (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;

{
  public static final Test A;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM

  public static final Test B;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM

  public static final Test C;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM

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

  public static Test valueOf(java.lang.String);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: ldc_w         #4                  // class Test
         3: aload_0
         4: invokestatic  #5                  // Method java/lang/Enum.valueOf:(
Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
         7: checkcast     #4                  // class Test
        10: areturn
      LineNumberTable:
        line 1: 0

  static {};
    flags: ACC_STATIC
    Code:
      stack=4, locals=0, args_size=0
         0: new           #4                  // class Test
         3: dup
         4: ldc           #7                  // String A
         6: iconst_0
         7: invokespecial #8                  // Method "":(Ljava/lang/Str
ing;I)V
        10: putstatic     #9                  // Field A:LTest;
        13: new           #4                  // class Test
        16: dup
        17: ldc           #10                 // String B
        19: iconst_1
        20: invokespecial #8                  // Method "":(Ljava/lang/Str
ing;I)V
        23: putstatic     #11                 // Field B:LTest;
        26: new           #4                  // class Test
        29: dup
        30: ldc           #12                 // String C
        32: iconst_2
        33: invokespecial #8                  // Method "":(Ljava/lang/Str
ing;I)V
        36: putstatic     #13                 // Field C:LTest;
        39: iconst_3
        40: anewarray     #4                  // class Test
        43: dup
        44: iconst_0
        45: getstatic     #9                  // Field A:LTest;
        48: aastore
        49: dup
        50: iconst_1
        51: getstatic     #11                 // Field B:LTest;
        54: aastore
        55: dup
        56: iconst_2
        57: getstatic     #13                 // Field C:LTest;
        60: aastore
        61: putstatic     #1                  // Field $VALUES:[LTest;
        64: return
      LineNumberTable:
        line 2: 0
        line 1: 39
}

结论如下:
1、java.lang.Enum<ElementType>,而编译后是public final class Test extends java.lang.Enum<Test>推不出Test是ElementType的子类这个结果。如果想导出这个结果,应该是Enum<? extends ElementType>。

这里Test和ElementType一点关系都没有。而恰恰相反,Enum的声明是:Enum<? extends Enum<E>>,即后面这个泛型里必须是Enum子类。所以合理的推理是这样的:Test是Enum的子类,ElementType也是Enum的子类。

2、为什么ElementType会有values()和valueOf()方法,这不是刚好,是因为ElementType本身也是Enum的子类,编译时自动添加了这些方法。

3、任何类也不可能是ElementType的子类,因为任何enum编译后都是final修饰的,除非它的某个枚举量有class body,而ElementType没有。final修饰的类不可继承。

一句话总结:编译器自动生成。

0 0
原创粉丝点击