在上一篇博客中介绍了《Class文件结构》,其中就提到了一个例子,下面我们依然根据该例子的字节码来对方法的执行流程进行讲解。
public class TestClass{
- private int num;
- public int inc(){
- for(int i=0; i<10; i++){
- num = i;
- }
- return num;
- }
- public static void main(String[] args){
- new TestClass().inc();
- }
- }
使用javap -verbose命令反编译后,输出常量表和字节码如下:
- D:\JVM>javap -verbose TestClass
- Compiled from "TestClass.java"
- public class TestClass extends java.lang.Object
- SourceFile: "TestClass.java"
- minor version: 0
- major version: 50
- Constant pool:
- const #1 = Method #6.#20; // java/lang/Object."<init>":()V
- const #2 = Field #3.#21; // TestClass.num:I
- const #3 = class #22; // TestClass
- const #4 = Method #3.#20; // TestClass."<init>":()V
- const #5 = Method #3.#23; // TestClass.inc:()I
- const #6 = class #24; // java/lang/Object
- const #7 = Asciz num;
- const #8 = Asciz I;
- const #9 = Asciz <init>;
- const #10 = Asciz ()V;
- const #11 = Asciz Code;
- const #12 = Asciz LineNumberTable;
- const #13 = Asciz inc;
- const #14 = Asciz ()I;
- const #15 = Asciz StackMapTable;
- const #16 = Asciz main;
- const #17 = Asciz ([Ljava/lang/String;)V;
- const #18 = Asciz SourceFile;
- const #19 = Asciz TestClass.java;
- const #20 = NameAndType #9:#10;// "<init>":()V
- const #21 = NameAndType #7:#8;// num:I
- const #22 = Asciz TestClass;
- const #23 = NameAndType #13:#14;// inc:()I
- const #24 = Asciz java/lang/Object;
- {
- public TestClass();
- 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
- public int inc();
- Code:
- Stack=2, Locals=2, Args_size=1
- 0: iconst_0 //定义一个常量0,放入操作数栈
- 1: istore_1 //把该常量弹出栈顶存入到局部变量表
- 2: iload_1 //把该局部变量放入操作数栈
- 3: bipush 10 //把常量10放入操作数栈
- 5: if_icmpge 19 //把i和10进行比较
- 8: aload_0 //加载局部变量表index为0的变量放入操作数栈
- 9: iload_1 //加载局部变量表index为1的变量放入操作数栈
- 10: putfield #2; //Field num:I //把i的值赋给num字段
- 13: iinc 1, 1 //局部变量i自增1
- 16: goto 2 //跳转到第2行
- 19: aload_0 //加载局部变量表index为0的变量放入操作数栈
- 20: getfield #2; //Field num:I //获取字段num的值
- 23: ireturn //返回
- LineNumberTable:
- line 5: 0
- line 6: 8
- line 5: 13
- line 8: 19
- StackMapTable: number_of_entries = 2
- frame_type = 252 /* append */
- offset_delta = 2
- locals = [ int ]
- frame_type = 250 /* chop */
- offset_delta = 16
- public static void main(java.lang.String[]);
- Code:
- Stack=2, Locals=1, Args_size=1
- 0: new #3; //class TestClass
- 3: dup
- 4: invokespecial #4; //Method "<init>":()V //调用实例初始化方法
- 7: invokevirtual #5; //Method inc:()I //调用普通方法inc()
- 10: pop
- 11: return
- LineNumberTable:
- line 12: 0
- line 13: 11
- }
方法的调用指令分为以下几种:
- invokevirtual指令用于调用所有的虚方法。
- invokeinterface指令用于调用接口方法,它会在运行时搜索一个实现了这个接口方法的对象,找出适合的方法进行调用。
- invokespecial指令用于调用一些需要特殊处理的实例方法,包括实例构造器<init>化方法、私有方法和父类方法。
- invokestatic指令用于调用静态方法(static方法)。
其它具体的指令可以参考:字节码指令集