Enumerations disassembled with javap do not display constructor parameters

When I disassemble enumeration with javap, the implicit constructor parameter of enumeration seems to be missing. I can't figure out why

This is an enumeration:

enum Foo { X }

I compile and disassemble (on Java 8u60) using the following command:

javac Foo.java && javap -c -p Foo

This is my output:

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
}

My confusion is the private constructor used to instantiate each enumeration constant Disassembly shows that it has no parameters (private foo();), But it must have parameters For example, you can see the load instruction to read the passed enumeration constant name and sequence number and this pointer and pass them to the superclass constructor, which requires them The code in the static initialization block also shows that it pushes these parameters onto the stack before calling the constructor

Now I assume that this is just an insignificant error in javap, but when I compile the same enumeration with the eclipse compiler and use javap disassembly, the constructors are exactly the same, except that the parameters show:

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
}

My question is: what is the difference between javac compiled enumerations and eclipse compiled enumerations, so that javap does not display the constructor parameters of javac compiled enumerations? Is this an error (in javap, javac, or eclipse)?

Solution

The parameters and return types of methods in class files are described by method descriptor

Introduce generics in 1.5 Other information is introduced into the class file format method signature

"Method descriptor" is used to describe the method after type erasure, and "method signature" also contains general type information

Now javap prints out the method signature (with more information), and when the - V flag is set, it also prints the descriptor

This indicates that the constructor of enum class generated by javac also has a method descriptor with parameter types of string and int It is now clear why elipse and javac both generate code Both use parameters string and int to call private constructors

What else to explain: why does javac create a signature that is completely different from the descriptor - not involving generics?

In any case, the behavior of javac about enumerating constructors leads to other faults. The error report of javac is filed:

The following comments and case classification show that this is a real mistake in javac

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>