一分钟系列:(1+2)*500是如何在JVM中运算的?
java之所以能够实现write Once,Run AnyWhere,就在于java文件被编译为class字节码运行于JVM上,而不是像c语言那种编译为二进制文件运行于CPU的寄存器。
看如下源码,我们把表达式放在了类的实例方法cal中。
public class Test{
public int cal(){
int a = 1;
int b = 2;
int c = 500;4
return (a + b) * c ;
}
}
经过javac编译后,在用javap -verbose反编译出来,看到如下字节码
stack=2, locals=4, args_size=1
0: iconst_1
1: istore_1
2: iconst_2
3: istore_2
4: sipush 500
7: istore_3
8: iload_1
9: iload_2
10: iadd
11: iload_3
12: imul
13: ireturn
stack=2: 表示这段代码的深度为2的操作数栈(操作数栈是用于支持虚拟机进行方法调用和方法执行的数据结构又:操作数栈,局部变量表,动态链接,方法返回地址等组成),
locals=4: 表示需要4个slot的局部变量空间,slot是局部变量的基本单位,
args_size=1表示这个函数有一个参数,可能很多读者到这里很疑惑,明明是一个无参的方法,还记得你可以在实例方法中使用this这个关键词获取对象的实例方法,属性吗,其实这里是javac编译器编译的时候把对this关键字的访问转变为对一个普通方法参数的访问;
首先执行便偏移地址为0的指令,iconst_1表示将int类型的常量1入操作数栈
偏移地址1:istore_1表示将操作数栈顶的整形值出栈并且存放在第一个局部变量slot中,
之后的偏移地址2~7是分别把2,500放入到第2,3局部变量slot中。
偏移地址8,9指令iload_1,iload_2分别把局部变量表中第1,2的slot入操作栈。
偏移地址10指令iadd表示把操作数栈中两个元素出栈做整型加法,结果入栈
偏移地址11指令iload_3表示把局部变量表中的第3的slot入操作数栈.
偏移地址12指令imul表示把操作数栈中的两个元素做整形乘法,并且将结果入栈。
偏移地址13指令ireturn表示将结束方法执行并将操作数栈定的整形值返回给此方法的调用者。