用javap反汇编的java枚举不显示构造函数参数
当我用javap反汇编一个enum时,enum的隐式构造函数参数似乎丢失了,我不知道为什么
下面是一个枚举:
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
指针,并将它们传递给the superclass constructor,这需要它们。静态初始值设定项块中的代码还显示,它在调用构造函数之前将这些参数推送到堆栈上
现在我假设这只是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编译的枚举和Eclipse编译的枚举在物理上有什么不同,导致javap不显示javac编译的枚举的构造函数参数?这是一个bug(在javap、javac或Eclipse中)
# 1 楼答案
类文件中方法的参数和返回类型由method descriptor描述
随着1.5中泛型的引入。在类文件格式method signature中引入了其他信息
“方法描述符”用于描述类型删除后的方法,“方法签名”还包含泛型类型信息
现在
javap
打印出方法签名(其中包含更多信息),当设置-v
标志时,它还打印描述符这还表明
javac
生成的枚举类的构造函数有一个参数类型为String
和int
的方法描述符。 现在也很清楚为什么Elipse和javac生成的代码都能工作。两者都使用参数String
和int
调用私有构造函数还有什么需要解释的:为什么
javac
创建了一个与描述符完全不同的签名——不涉及泛型无论如何,
javac
关于枚举构造函数的行为导致了other troubles,而javac
的错误报告是filed:下面的评论和案例分类表明,这是
javac
中的一个真正的缺陷