JVM系列(1)-变量
前言
这段时间一直在看JVM相关的书籍,虽然有点难,至少到目前为止还没有放弃。写这篇文章的目的:当做自己这段时间学习的小回顾。本章主要通过几个代码片段,分析下局部变量表与操作数栈之间的数据传递关系,重点讲解iload
,istore
,iconst_<n>
,iadd
命令
提前了解
JVM的几个概念
局部变量表:每个栈帧内部都包含一组称为局部变量表的变量列表
操作数栈:每个栈帧内部都包含一个操作数栈
iconst_0:把int型的0值压入操作数栈
iload:将一个局部变量加载到操作数栈上
istore:将一个数值从操作数栈上存储到局部变量表中
iadd:返回栈顶的两个元素做加法运算,并加结果压栈
如何使用dos查看字节码文件
首先通过dos进入TestApp.class所在的目录,然后运行命令javap -c TestApp
,即可看到编译后的字节码文件
程序片段一
以下是一个java源代码
public void test1(){ int c=0; }
编译后的字节码
public void test1(); Code: 0: iconst_0 1: istore_1 2: return
代码分析
因为test1()
是一个实例方法,所以在局部变量表中,索引为0的位置会保存该方法所在类的引用(this),所以才会出现istore_1
而不是istore_0
。
我们对int c = 0
做下拆解,一个常量0,一个变量c。
0: iconst_0 //将常量0压入操作数栈 1: istore_1 //将栈顶出栈,即c=0 2: return //因为是void,没有返回值
程序片段二
Java源代码如下
public static void test2(){ int c=0; }
编译后的字节码文件
public static void test2(); Code: 0: iconst_0 1: istore_0 2: return
分析
因为test2()
是一个静态的方法,不会在局部变量表中插入任何数据。所以你看到的是istore_0
而不是像程序片段一
中的istore_1
。其他分析跟程序片段一
相同
程序片段三
java源代码
public int test3(){ int c=0; return c; }
编译后的字节码
public int test3(); Code: 0: iconst_0 1: istore_1 2: iload_1 3: ireturn
分析
0: iconst_0 //将常量0压栈 1: istore_1 //将栈顶出栈,及c=0 2: iload_1 //将变量c压入栈顶 3: ireturn //返回栈定元素
程序片段四
Java源代码
public int test4(int a,int b){ int c=0; return a+b; }
编译后的字节码
public int test4(int, int); Code: 0: iconst_0 1: istore_3 2: iload_1 3: iload_2 4: iadd 5: ireturn
** 分析
因为test4(int a,int b)
是实例方法,所以在局部变量表
索引为0的位置会插入this
。
因为test4(int a,int b)
带有两个参数,所以在局部变量索引
索引为1的位置插入a,在索引为2的位置插入b。
0: iconst_0 //将常量0压栈 1: istore_3 //将栈顶出栈,即c=0,将c存储到局部变量表索引为3的位置 2: iload_1 //将局部变量表中索引为1的变量压栈,即a压栈 3: iload_2 //将局部变量表中索引为2的变量压栈,即b压栈 4: iadd //将栈顶两个元素出栈,做加法,然后把结果再入栈(即a,b出栈,将a+b入栈) 5: ireturn //返回a+b的值
程序片段五
java源代码
public int test5(int a,int b){ int c=0; c= a+b; return c; }
编译后的字节码
public int test5(int, int); Code: 0: iconst_0 1: istore_3 2: iload_1 3: iload_2 4: iadd 5: istore_3 6: iload_3 7: ireturn
分析
0: iconst_0 //将常量0压栈 1: istore_3 //将栈顶出栈,及c=0 2: iload_1 //从局部变量表中加载索引为1的变量压栈,即a压栈 3: iload_2 //从局部变量表中加载索引为2的变量压栈,即b压栈 4: iadd //将栈顶两个元素出栈,做加法,然后将结果压栈,及a+b压栈 5: istore_3 //将栈顶元素出栈,并保存到局部变量表中,即c=a+b 6: iload_3 //从局部变量表中加载索引为3的变量压栈,即c压栈 7: ireturn //返回栈顶元素,即返回c