JVM指令是面向虚拟机的“机器语言”,透过JVM指令可以知道某些代码的真面目,更深入的理解一些匪夷所思的现象。下面看看几个案例:
分析案例1
JVM的指令和运行时数据区相辅相成,所有的JVM指令都能在《JVMS》规范上找到,这一章主要分析 指令结合运行时数据区。
首先看下面一个小程序,目测一下该程序的运行结果:
public static void main(String[] args) {int i = 8;i = i++;System.out.println(i);}
结果是8。我一开始看到还是蒙蔽的,为啥呢?为啥呢?让我们打开它的字节码文件分析一下:
0 bipush 82 istore_13 iload_14 iinc 1 by 17 istore_18 getstatic #2 <java/lang/System.out>11 iload_112 invokevirtual #3 <java/io/PrintStream.println>15 return
(前面的1、2、3、4是行号,后面的0、2、3、4是字节偏移)
bipush 8,根据官方手册,得知该条指令表示以int类型将操作数压入操作数栈中istore_1表示将操作数栈顶的int类型的数弹出并设置给local variable table的索引为1的变量。local variable table如下所示:

iload_1表示将local variable table的索引为1的变量的值压入到操作数栈顶iinc 1 by 1,第一个1表示local variable table的索引为1的变量;第二个1表示要递增的步长。注意该指令对操作数栈无影响。istore_1表示将栈顶的int类型的值存入local variable table里索引为1的变量
所以最终i的值为8
分析案例2
现在有一个类:
public class TestTarget {private int intValue = 100;public void sayHello(){System.out.println(intValue);}}
有一个测试程序:
public final class App {public static void main(String[] args) {TestTarget testTarget = new TestTarget();testTarget.sayHello();}}
然后主要查看一下 TesetTarget 编译后的字节码文件:
TestTarget.sayHello() 方法里面的局部变量表里,第一个变量是 this ,该小程序只是为了说明为什么我们可以调用 this 。
这里有疑问,super 是怎么调用的呢?调用super的方法也是 invokespecial 这是为啥?
分析案例3
public final class App {public static void main(String[] args) {TestTarget testTarget = new TestTarget();}}

- new创建
TestTarget对象,并将对象的引用放到操作数栈顶 - dup,复制操作数栈顶的对象
- invokespecial,调用栈顶对象的初始化方法
- astore_1,把栈顶元素保存到 局部变量表里下标为1的变量里
说明创建一个对象至少有2步,创建对象,然后调用对象的初始化方法。 new 指令底部有这样一个描述:
The new instruction does not completely create a new instance; instance creation is not completed until an instance initialization method (§2.9) has been invoked on the uninitialized instance.
new 指令没有完整的创建一个实例,未初始化的实例直到调用了初始化方法才算完整
