Compiling your enum class and disassembling with javap -verbose
gives this (partial) output:
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
By the time that an enum is compiled, it's just an ordinary Java .class
file, whose only distinguishing features at runtime are the fact that it extends Enum
and has the ACC_ENUM
flag set; everything else is just plain bytecode.
To set up the enum constants, including their names, the compiler could theoretically use complicated reflection to derive the names from the value names, but instead it's far simpler and just as effective to inline the names as string constants. The static initializer loops through the names, calling the private constructor to instantiate the value instances and assign them to the private $VALUES
array.
As these strings are in the constant pool, the usual deduplication logic then applies. toString()
returns the same object because its default implementation is simply to return name
.