gpt4 book ai didi

java - 用 javap 反汇编的枚举不显示构造函数参数

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:32:02 25 4
gpt4 key购买 nike

当我用 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)构造函数。反汇编表明它不带参数 (private Foo();),但它确实带参数。例如,您可以看到 load 指令读取传递的枚举常量名称和序号,以及 this 指针,并将它们传递给 the superclass constructor。 ,这需要他们。静态初始化程序 block 中的代码还表明它在调用构造函数之前将这些参数压入堆栈。

现在我会假设这只是 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 编译的枚举的构造函数参数?这种差异是否是错误(在 javap、javac 或 Eclipse 中)?

最佳答案

类文件中方法的参数和返回类型由 method descriptor 描述。 .

随着 1.5 中泛型的引入。在类文件格式中引入了附加信息,method signature .

“方法描述符”用于描述类型删除后的方法,“方法签名”额外包含泛型类型信息。

现在 javap 打印出方法签名(包含更多信息),当设置了 -v 标志时,它还会打印描述符。

这表明 javac 生成的枚举类的构造函数也有一个参数类型为 Stringint 的方法描述符。现在也很清楚为什么 Elipse 和 javac 生成的代码都能工作。两者都使用参数 Stringint 调用私有(private)构造函数。

还有什么需要解释的:为什么 javac 创建一个完全不同于描述符的签名——不涉及泛型?

无论如何,javac 关于枚举构造函数的行为导致了other troubles javac 的错误报告是 filed :

There is no need for an enum declaration's constructor to have a Signature attribute storing a method signature if 1) the constructor isn't generic and 2) its formal parameter types are neither parameterized types nor type variables. It's a bug if javac expects a Signature attribute for the constructor written above.

下面的评论和案例的分类表明这是 javac 中的一个真正的错误。

关于java - 用 javap 反汇编的枚举不显示构造函数参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32829143/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com