0 Replies Latest reply: May 7, 2014 3:00 AM by 58e21238-2d7f-4e5f-9be6-9adcad70315d RSS

    javap and anonymous classes

    58e21238-2d7f-4e5f-9be6-9adcad70315d

      Hello!

      I have a question regarding the output generated by the javap disassembler.

      Lets say we have the following two classes:

       

      public class A {
           public int x = 0;
      
           public int getX() {
                return x;
           }
      }
      

       

      and

        

      public class Test {
           public static void main(String [] args) {
                A a = new A() {
                     public int getX() {
                          return 1;
                     }
                };
           int x = a.getX();
           }
      }
      

      The output generated after running

      javac -g A.java Test.java

      and

      javap -p -v -s A.class Test$1.class Test.class

      is:

       

      Classfile /home/stefan/Projects/javap-test/A.class
        Last modified May 7, 2014; size 337 bytes
        MD5 checksum c92d7af447fa7717520d721a44940eb3
        Compiled from "A.java"
      public class A
        SourceFile: "A.java"
        minor version: 0
        major version: 51
        flags: ACC_PUBLIC, ACC_SUPER
      Constant pool:
         #1 = Methodref          #4.#18         //  java/lang/Object."<init>":()V
         #2 = Fieldref           #3.#19         //  A.x:I
         #3 = Class              #20            //  A
         #4 = Class              #21            //  java/lang/Object
         #5 = Utf8               x
         #6 = Utf8               I
         #7 = Utf8               <init>
         #8 = Utf8               ()V
         #9 = Utf8               Code
        #10 = Utf8               LineNumberTable
        #11 = Utf8               LocalVariableTable
        #12 = Utf8               this
        #13 = Utf8               LA;
        #14 = Utf8               getX
        #15 = Utf8               ()I
        #16 = Utf8               SourceFile
        #17 = Utf8               A.java
        #18 = NameAndType        #7:#8          //  "<init>":()V
        #19 = NameAndType        #5:#6          //  x:I
        #20 = Utf8               A
        #21 = Utf8               java/lang/Object
      {
        public int x;
          Signature: I
          flags: ACC_PUBLIC
      
      
        public A();
          Signature: ()V
          flags: ACC_PUBLIC
          Code:
            stack=2, locals=1, args_size=1
               0: aload_0       
               1: invokespecial #1                  // Method java/lang/Object."<init>":()V
               4: aload_0       
               5: iconst_0      
               6: putfield      #2                  // Field x:I
               9: return        
            LineNumberTable:
              line 1: 0
              line 2: 4
            LocalVariableTable:
              Start  Length  Slot  Name   Signature
                     0      10     0  this   LA;
      
      
        public int getX();
          Signature: ()I
          flags: ACC_PUBLIC
          Code:
            stack=1, locals=1, args_size=1
               0: aload_0       
               1: getfield      #2                  // Field x:I
               4: ireturn       
            LineNumberTable:
              line 5: 0
            LocalVariableTable:
              Start  Length  Slot  Name   Signature
                     0       5     0  this   LA;
      }
      Classfile /home/stefan/Projects/javap-test/Test$1.class
        Last modified May 7, 2014; size 406 bytes
        MD5 checksum 997ccb68d293f425eed24512bc5fdbf9
        Compiled from "Test.java"
      final class Test$1 extends A
        SourceFile: "Test.java"
        EnclosingMethod: #18.#19                // Test.main
        InnerClasses:
             static #2; //class Test$1
        minor version: 0
        major version: 51
        flags: ACC_FINAL, ACC_SUPER
      Constant pool:
         #1 = Methodref          #3.#20         //  A."<init>":()V
         #2 = Class              #21            //  Test$1
         #3 = Class              #22            //  A
         #4 = Utf8               <init>
         #5 = Utf8               ()V
         #6 = Utf8               Code
         #7 = Utf8               LineNumberTable
         #8 = Utf8               LocalVariableTable
         #9 = Utf8               this
        #10 = Utf8               
        #11 = Utf8               InnerClasses
        #12 = Utf8               LTest$1;
        #13 = Utf8               getX
        #14 = Utf8               ()I
        #15 = Utf8               SourceFile
        #16 = Utf8               Test.java
        #17 = Utf8               EnclosingMethod
        #18 = Class              #23            //  Test
        #19 = NameAndType        #24:#25        //  main:([Ljava/lang/String;)V
        #20 = NameAndType        #4:#5          //  "<init>":()V
        #21 = Utf8               Test$1
        #22 = Utf8               A
        #23 = Utf8               Test
        #24 = Utf8               main
        #25 = Utf8               ([Ljava/lang/String;)V
      {
        Test$1();
          Signature: ()V
          flags: 
          Code:
            stack=1, locals=1, args_size=1
               0: aload_0       
               1: invokespecial #1                  // Method A."<init>":()V
               4: return        
            LineNumberTable:
              line 4: 0
            LocalVariableTable:
              Start  Length  Slot  Name   Signature
                     0       5     0  this   LTest$1;
      
      
        public int getX();
          Signature: ()I
          flags: ACC_PUBLIC
          Code:
            stack=1, locals=1, args_size=1
               0: iconst_1      
               1: ireturn       
            LineNumberTable:
              line 6: 0
            LocalVariableTable:
              Start  Length  Slot  Name   Signature
                     0       2     0  this   LTest$1;
      }
      Classfile /home/stefan/Projects/javap-test/Test.class
        Last modified May 7, 2014; size 495 bytes
        MD5 checksum 5ef25a1fdb4c9483b7573a8c9a0c993a
        Compiled from "Test.java"
      public class Test
        SourceFile: "Test.java"
        InnerClasses:
             static #2; //class Test$1
        minor version: 0
        major version: 51
        flags: ACC_PUBLIC, ACC_SUPER
      Constant pool:
         #1 = Methodref          #6.#26         //  java/lang/Object."<init>":()V
         #2 = Class              #27            //  Test$1
         #3 = Methodref          #2.#26         //  Test$1."<init>":()V
         #4 = Methodref          #28.#29        //  A.getX:()I
         #5 = Class              #30            //  Test
         #6 = Class              #31            //  java/lang/Object
         #7 = Utf8               
         #8 = Utf8               InnerClasses
         #9 = Utf8               <init>
        #10 = Utf8               ()V
        #11 = Utf8               Code
        #12 = Utf8               LineNumberTable
        #13 = Utf8               LocalVariableTable
        #14 = Utf8               this
        #15 = Utf8               LTest;
        #16 = Utf8               main
        #17 = Utf8               ([Ljava/lang/String;)V
        #18 = Utf8               args
        #19 = Utf8               [Ljava/lang/String;
        #20 = Utf8               a
        #21 = Utf8               LA;
        #22 = Utf8               x
        #23 = Utf8               I
        #24 = Utf8               SourceFile
        #25 = Utf8               Test.java
        #26 = NameAndType        #9:#10         //  "<init>":()V
        #27 = Utf8               Test$1
        #28 = Class              #32            //  A
        #29 = NameAndType        #33:#34        //  getX:()I
        #30 = Utf8               Test
        #31 = Utf8               java/lang/Object
        #32 = Utf8               A
        #33 = Utf8               getX
        #34 = Utf8               ()I
      {
        public Test();
          Signature: ()V
          flags: ACC_PUBLIC
          Code:
            stack=1, locals=1, args_size=1
               0: aload_0       
               1: invokespecial #1                  // Method java/lang/Object."<init>":()V
               4: return        
            LineNumberTable:
              line 1: 0
            LocalVariableTable:
              Start  Length  Slot  Name   Signature
                     0       5     0  this   LTest;
      
      
        public static void main(java.lang.String[]);
          Signature: ([Ljava/lang/String;)V
          flags: ACC_PUBLIC, ACC_STATIC
          Code:
            stack=2, locals=3, args_size=1
               0: new           #2                  // class Test$1
               3: dup           
               4: invokespecial #3                  // Method Test$1."<init>":()V
               7: astore_1      
               8: aload_1       
               9: invokevirtual #4                  // Method A.getX:()I
              12: istore_2      
              13: return        
            LineNumberTable:
              line 4: 0
              line 10: 8
              line 11: 13
            LocalVariableTable:
              Start  Length  Slot  Name   Signature
                     0      14     0  args   [Ljava/lang/String;
                     8       6     1     a   LA;
                    13       1     2     x   I
      }
      

       

      The a.getX() call from the main method of class Test is translated into bytecode as invokevirtual #4, where #4 is a reference to the getX() method from class A. If I run the example, the getX() method from the anonymous class Test$1 gets invoked as expected. Shouldn't the index of invokevirtual be a reference to the getX() method from class Test$1?