我试图了解规范中是否有理由说明内部类的Java描述符和签名之间的差异。 (我在这里直接查看类文件的内容,但是我使用javap进行说明)。

(n.b.我已经在JDK 1.6.0_33和1.7.0_05上进行了尝试,当使用来自Java 7的javap进行查看时,它们都有相同的问题-根据下面的Sean的回答,java 6的javap似乎没有显示任何通用签名信息。

更新:感谢那些讨论-我的看法是

  • 描述符(不包含常规信息)是正确的。
  • 签名(该方法的属性,并且确实包含通用信息)不正确。 方法的SIGNATURE的相关ConstPool条目是“ConstantUTF8 [(Ljava/util/list )V]”
  • Java 6中的Javap不会查看签名,而只能查看描述符。 (我的猜测!)

  • 万一有人怀疑,我没有使用JAVAP就打了这个,只是我自己看了类文件,我只是用javap来显示它。 (因此不太可能是javap错误)。

    考虑:
    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;
        }....
    


    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;
        }.....
    

    如果您查看内部类上javap -cs的输出,它们的区别令人惊讶!

    公共(public)org.benf.cfr.tests.InnerClassTest1 $ Inner1( org.benf.cfr.tests.InnerClassTest1, java.util.List);
    签名:(Lorg/benf/cfr/tests/InnerClassTest1; Ljava/util/List;)V



    公共(public)org.benf.cfr.tests.InnerClassTest2 $ Inner1(java.util.List );
    签名:(Lorg/benf/cfr/tests/InnerClassTest2; Ljava/util/List;)V

    ...使用泛型的那个缺少外部类的隐式参数! (在InnerClassTest1中正确存在)。

    我在类文件文档中找不到任何可以解释的内容-有人知道为什么会这样吗?

    谢谢!



    更新 -

    我已将示例文件放置在http://www.benf.org/files/innerClassTest.tgz

    给定下面的Sean答案,我尝试在java 6上使用javap,并且看到两者的输出相同,没有通用信息-这使我相信Java 6的javap不会显示完整的签名信息?

    我在1.7.0_05-b06上使用javap获得的确切输出是
    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
    }
    

    最佳答案

    使用上面的代码并使用JDK 1.6.0_33,我得到以下输出:

    src\test>javap -c -s InnerClassTest1$Inner1
    Compiled from "InnerClassTest1.java"
    public class test.InnerClassTest1$Inner1 extends java.lang.Object{
    final test.InnerClassTest1 this$0;
      Signature: Ltest/InnerClassTest1;
    
    public test.InnerClassTest1$Inner1(test.InnerClassTest1, java.util.List);
      Signature: (Ltest/InnerClassTest1;Ljava/util/List;)V
      Code:
       0:   aload_0
       1:   aload_1
       2:   putfield        #1; //Field this$0:Ltest/InnerClassTest1;
       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:   iload_1
       1:   ireturn
    }
    
    src\test>javap -c -s InnerClassTest2$Inner1
    Compiled from "InnerClassTest2.java"
    public class test.InnerClassTest2$Inner1 extends java.lang.Object{
    final test.InnerClassTest2 this$0;
      Signature: Ltest/InnerClassTest2;
    
    public test.InnerClassTest2$Inner1(test.InnerClassTest2, java.util.List);
      Signature: (Ltest/InnerClassTest2;Ljava/util/List;)V
      Code:
       0:   aload_0
       1:   aload_1
       2:   putfield        #1; //Field this$0:Ltest/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:   iload_1
       1:   ireturn
    
    }
    

    唯一的区别是我的实现(使代码可以编译):
        public int getX(int i) {
            return i;
        }
    

    以及您的软件包名称可能不同的事实(org.benf.cfr.tests?)。

    除此之外,我的输出几乎相同。代码中是否还有其他差异可以解释您所看到的内容?从我对编译过程和类文件的了解中,我不希望看到输出有所不同。

    好问题-找出原因的原因很有趣

    关于Java内部类描述符和签名属性之间不一致? (类文件),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15131040/

    10-11 01:32