有如下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修饰的类不可继承。
一句话总结:编译器自动生成。