编译你的枚举类并反汇编javap -verbose
得到这个(部分)输出:
final class User extends java.lang.Enum<User>
minor version: 0
major version: 52
flags: ACC_FINAL, ACC_SUPER, ACC_ENUM
Constant pool:
#7 = String #13 // BASIC
#9 = Fieldref #4.#38 // User.BASIC:LUser;
#10 = String #15 // PREMIUM
#11 = Fieldref #4.#39 // User.PREMIUM:LUser;
#13 = Utf8 BASIC
#15 = Utf8 PREMIUM
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=4, locals=0, args_size=0
0: new #4 // class User
3: dup
4: ldc #7 // String BASIC
6: iconst_0
7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #9 // Field BASIC:LUser;
13: new #4 // class User
16: dup
17: ldc #10 // String PREMIUM
19: iconst_1
20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #11 // Field PREMIUM:LUser;
26: iconst_2
27: anewarray #4 // class User
30: dup
31: iconst_0
32: getstatic #9 // Field BASIC:LUser;
35: aastore
36: dup
37: iconst_1
38: getstatic #11 // Field PREMIUM:LUser;
41: aastore
42: putstatic #1 // Field $VALUES:[LUser;
45: return
LineNumberTable:
line 1: 0
在编译枚举时,它只是一个普通的 Java.class
文件,它在运行时唯一的区别在于它扩展Enum
并ACC_ENUM
设置了标志。其他一切都只是普通的字节码。
要设置枚举常量(包括它们的名称),编译器理论上可以使用复杂的反射从值名称中派生名称,但内联名称和字符串常量一样简单且有效。静态初始化程序遍历名称,调用私有构造函数来实例化值实例并将它们分配给私有$VALUES
数组。
由于这些字符串位于常量池中,因此通常的重复数据删除逻辑适用。toString()
返回相同的对象,因为它的默认实现只是简单地返回name
。