enum クラスをコンパイルして逆アセンブルすると、次の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
enum がコンパイルされるまでには、それはただの普通の Java.class
ファイルであり、実行時に唯一の特徴は、それが拡張されEnum
、ACC_ENUM
フラグが設定されているという事実だけです。他のすべては単なるバイトコードです。
名前を含む列挙定数を設定するために、コンパイラは理論的には複雑なリフレクションを使用して値の名前から名前を派生させることができますが、代わりに名前を文字列定数とインライン化する方がはるかに簡単で効果的です。静的初期化子は名前をループし、プライベート コンストラクターを呼び出して値のインスタンスをインスタンス化し、それらをプライベート$VALUES
配列に割り当てます。
これらの文字列は定数プールにあるため、通常の重複排除ロジックが適用されます。toString()
デフォルトの実装は単純に return であるため、同じオブジェクトを返しname
ます。