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?