javap で列挙型を逆アセンブルすると、列挙型の暗黙的なコンストラクター引数が欠落しているように見え、その理由がわかりません。
列挙型は次のとおりです。
enum Foo { X }
これを(Java 8u60で)次のコマンドでコンパイルおよび逆アセンブルします。
javac Foo.java && javap -c -p Foo
そして、ここに私が得る出力があります:
final class Foo extends java.lang.Enum<Foo> {
public static final Foo X;
private static final Foo[] $VALUES;
public static Foo[] values();
Code:
0: getstatic #1 // Field $VALUES:[LFoo;
3: invokevirtual #2 // Method "[LFoo;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[LFoo;"
9: areturn
public static Foo valueOf(java.lang.String);
Code:
0: ldc #4 // class Foo
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class Foo
9: areturn
private Foo(); // <--- here
Code:
0: aload_0
1: aload_1
2: iload_2
3: invokespecial #6 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
6: return
static {};
Code:
0: new #4 // class Foo
3: dup
4: ldc #7 // String X
6: iconst_0
7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #9 // Field X:LFoo;
13: iconst_1
14: anewarray #4 // class Foo
17: dup
18: iconst_0
19: getstatic #9 // Field X:LFoo;
22: aastore
23: putstatic #1 // Field $VALUES:[LFoo;
26: return
}
私の混乱は、各列挙型定数をインスタンス化するために使用されるプライベートコンストラクターにあります。逆アセンブルは、引数をとらないことを示しています ( private Foo();
) が、確かに引数をとります。たとえばload
、渡された列挙定数の名前と序数、this
およびポインターを読み取り、それらを必要とするスーパークラスのコンストラクターに渡す命令を確認できます。静的イニシャライザ ブロックのコードは、コンストラクタを呼び出す前にこれらの引数をスタックにプッシュすることも示しています。
今、これは javap のあいまいなバグだと思っていたでしょうが、Eclipse のコンパイラでまったく同じ列挙型をコンパイルし、javap を使用してそれを逆アセンブルすると、コンストラクターは引数が表示されていることを除いてまったく同じです。
final class Foo extends java.lang.Enum<Foo> {
public static final Foo X;
private static final Foo[] ENUM$VALUES;
static {};
Code:
0: new #1 // class Foo
3: dup
4: ldc #12 // String X
6: iconst_0
7: invokespecial #13 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #17 // Field X:LFoo;
13: iconst_1
14: anewarray #1 // class Foo
17: dup
18: iconst_0
19: getstatic #17 // Field X:LFoo;
22: aastore
23: putstatic #19 // Field ENUM$VALUES:[LFoo;
26: return
private Foo(java.lang.String, int); // <--- here
Code:
0: aload_0
1: aload_1
2: iload_2
3: invokespecial #23 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
6: return
public static Foo[] values();
Code:
0: getstatic #19 // Field ENUM$VALUES:[LFoo;
3: dup
4: astore_0
5: iconst_0
6: aload_0
7: arraylength
8: dup
9: istore_1
10: anewarray #1 // class Foo
13: dup
14: astore_2
15: iconst_0
16: iload_1
17: invokestatic #27 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V
20: aload_2
21: areturn
public static Foo valueOf(java.lang.String);
Code:
0: ldc #1 // class Foo
2: aload_0
3: invokestatic #35 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #1 // class Foo
9: areturn
}
私の質問は、javac でコンパイルされた列挙型と、javac でコンパイルされた列挙型のコンストラクター引数を javap が表示しない原因となる Eclipse でコンパイルされた列挙型の物理的な違いは何ですか? そして、この違いは (javap、javac、または Eclipse の) バグですか?