Enum parsed with javap does not show constructor arguments

When I parse the enum using javap, the arguments of the enumerator constructor pointer seem to be missing, and I cannot understand why.

Here's the listing:

enum Foo { X } 

I compile and parse this (in Java 8u60) with this command:

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

And here is the result that I get:

 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 with the private constructor used to instantiate each enum constant. Disassembly shows that it does not accept arguments ( private Foo(); ), but it certainly accepts arguments. For example, you can see load statements reading the passed enum constant name and serial number, as well as the this pointer and passing them to the superclass constructor , which requires them. The code in the static initializer block also shows that it pushes these arguments onto the stack before calling the constructor.

Now I would suggest that this is just an incomprehensible error in javap, but when I compile the exact same enumeration with the Eclipse compiler and parse it with javap, the constructor is exactly the same except for the arguments:

 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 physically different between the javac-compiled enum and the Eclipse compiler, which causes javap not to show constructor arguments for the javac-compiled enum? And is there any difference in error (in javap, in javac or Eclipse)?

+7
java enums javap .class-file ecj
source share
1 answer

The parameters and return type of the method inside the class file are described by the method handle.

With the introduction of generics in 1.5. additional information was introduced into the class file format, method signature .

The "method descriptor" is used to describe the method after the type has been erased; the "method signature" additionally contains information about the general type.

Now javap prints the method signature (which contains more information), and when the -v flag is set, it also prints a handle.

This shows that the constructor of the javac class generated by enum also has a method handle with String and int parameters. Now it’s also clear why Elipse and javac code work. Both invoke a private constructor with arguments String and int .

What else needs to be explained: why does javac create a signature that is generally different from the handle, are generics not involved?

In any case, javac behavior regarding the enum constructor caused other problems , and an error report for javac was sent :

It is not necessary that the enum declaration constructor does not have a signature attribute that stores the method signature if 1) the constructor is not general and 2) its formal parameter types are neither parameterized types nor type variables. This is an error if javac expects a signature attribute for the constructor written above.

The following comments and case classification suggest that this is a real bug in javac .

+3
source share

All Articles