I'm trying to understand if there's a reason in the spec for the discrepany between java descriptors and signatures for inner classes. (I'm looking directly at the content of the class files here, but I use javap to illustrate).
( n.b. I have tried this on JDK 1.6.0_33 and 1.7.0_05, both have the same issue when viewed with javap from Java 7 - java 6's javap doesn't seem to show any generic signature info, as per Sean's answer below. )
Update : Thanks to those discussing - my take is
- The descriptor (which doesn't contain generic information) is correct.
- The signature (which is an attribute of the method, and does contain generic information) is incorrect. The relevant ConstPool entry for SIGNATURE of the <init> method is " ConstantUTF8[(Ljava/util/list<TE;>)V] "
- Javap in Java 6 doesn't LOOK at the signature, just the descriptor. (My guess!)
In case anyone wonders, I hit this without using JAVAP, just looking at the class files myself, I am only using javap to show it. (so it's unlikely to be a javap bug).
Consider:
public class InnerClassTest1 {
public int getX() {
return new Inner1(new ArrayList<String>()).getX(4);
}
public class Inner1 {
private final List arg;
public Inner1(List arg) {
this.arg = arg;
}....
vs
public class InnerClassTest2 {
public int getX() {
return new Inner1(new ArrayList<String>()).getX(4);
}
public class Inner1<E> {
private final List<E> arg;
public Inner1(List<E> arg) {
this.arg = arg;
}.....
If you look at the output of javap -cs on the inner classes, they're surprisingly different!
public org.benf.cfr.tests.InnerClassTest1$Inner1(org.benf.cfr.tests.InnerClassTest1, java.util.List); Signature: (Lorg/benf/cfr/tests/InnerClassTest1;Ljava/util/List;)V
vs
public org.benf.cfr.tests.InnerClassTest2$Inner1(java.util.List<E>); Signature: (Lorg/benf/cfr/tests/InnerClassTest2;Ljava/util/List;)V
... the one which uses generics is missing the implicit parameter for the outer class! (it's correctly present in InnerClassTest1).
I can't find anything in the class file documentation to explain this - does anyone know why this might be?
Thanks!
Lee.
Update -
I've placed example files at http://www.benf.org/files/innerClassTest.tgz
Given Sean's answer below, I tried using javap on java 6, and I saw identical output for both, with no generic information - this leads me to believe that java 6's javap is not displaying full signature information?
The exact output I get using javap on 1.7.0_05-b06 is
public class org.benf.cfr.tests.InnerClassTest2$Inner1<E> {
final org.benf.cfr.tests.InnerClassTest2 this$0;
Signature: Lorg/benf/cfr/tests/InnerClassTest2;
public org.benf.cfr.tests.InnerClassTest2$Inner1(java.util.List<E>);
Signature: (Lorg/benf/cfr/tests/InnerClassTest2;Ljava/util/List;)V
Code:
0: aload_0
1: aload_1
2: putfield #1 // Field this$0:Lorg/benf/cfr/tests/InnerClassTest2;
5: aload_0
6: invokespecial #2 // Method java/lang/Object."<init>":()V
9: aload_0
10: aload_2
11: putfield #3 // Field arg:Ljava/util/List;
14: return
public int getX(int);
Signature: (I)I
Code:
0: iconst_2
1: ireturn
}
Using the code above and using JDK 1.6.0_33 I get the following output:
and the only differences are that my implementation has (to make the code compile):
and the fact that your package name is probably different (org.benf.cfr.tests ?).
Other than that though, my output is pretty much the same. Are there any other differences in the code that might explain what you're seeing? From what I know about the compilation process and class files I wouldn't expect to see a difference in the output.
Good question - be interesting to find out why you're seeing this
Using Javap on
InnerClassTest2$Inner1
givesDisassembling with Krakatau gives
As you can see, the Krakatau output shows that the descriptor is actually correct, but for some reason Javap isn't displaying it. One thing about Javap is that it tries to arrange the output so it looks more like Java. Perhaps this is a new feature introduced in JDK7 that tries to make disassembled generics look more like Java by hiding the compiler added parameters. Unfortunately this makes Javap (even more) useless for seeing what's really there.
Interesting catch!