使用javap反汇编的Enum不';不显示构造函数参数

使用javap反汇编的Enum不';不显示构造函数参数,java,enums,.class-file,javap,ecj,Java,Enums,.class File,Javap,Ecj,当我用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

当我用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
}

我的问题是:javac编译的枚举和Eclipse编译的枚举在物理上有什么不同,导致javap不显示javac编译的枚举的构造函数参数?这种差异是bug吗(在javap、javac或Eclipse中)?

类文件中方法的参数和返回类型由一个

随着1.5中泛型的引入。类文件格式中引入了其他信息,即

“方法描述符”用于描述类型擦除后的方法,“方法签名”还包含泛型类型信息

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

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

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

无论如何,
javac
关于enum构造函数的行为已经导致,
javac
的错误报告是:

枚举声明的构造函数不需要有 用于存储方法签名的签名属性(如果1)构造函数 不是泛型的,2)其形式参数类型也不是泛型的 参数化类型或类型变量。如果javac希望 上面编写的构造函数的签名属性


下面的评论和案例的分类表明这是
javac

中的一个真正的错误,猜测一下,
-g
标志的设置(控制调试信息的生成)。@CPerkins很好的假设,但我比较了
-g
(生成所有调试信息)和
-g:none
(不生成调试信息)并且似乎没有什么区别。您是否尝试了
-v
(verbose)标志?它至少应该向您显示构造函数的描述符。我猜
javac
标记了第一个参数
强制执行的
,这可能会使
javap
忽略它们。@Clashsoft有趣。“描述符”显示参数(
描述符:(Ljava/lang/String;I)V
),但我仍然不明白是什么导致了javac和Eclipse枚举之间的差异。正如我所说,
javap
可能忽略了
强制的
参数。我想Eclipse不会生成修饰符,而
javac
会生成修饰符。谢谢,这解释了差异。事实证明,javac确实包含显式定义签名中的d enum构造函数参数,而不是常量名和序号的两个隐式参数。虽然我不认为这是javac中的一个错误,但更多的是VM规范中的一个缺陷。VM规范的签名属性规则,例如它应该出现的时间和应该包含的内容,似乎定义模糊。内部类的构造函数也存在类似的问题,它有一个隐藏参数,用于将引用传递给外部类。例如:
class outer{class inner{inner(){}}
–构造函数在反汇编中显示为:
outer$inner(outer);
。但是如果构造函数是泛型的:
class outer{class Inner{Inner(){}}
,它在类文件中获得一个签名属性,javap将其反汇编为
Outer$Inner();
–参数突然不可见,这在javac和ECJ中都是如此。奇怪的东西!至少
-v
选项揭示了真相!
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
}