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
}