前言
这篇文章是在我学习了JVM相关知识之后。明白了我们编写的代码,也就是.java文件会被翻译成.class字节码文件运行在虚拟中。.class文件中其实存放的就是jvm虚拟机认识的一条条指令,指挥着JVM做我们想要他做的事情。但是我们并不清楚,我们的代码最终成为了何种指令?
看次篇博文知识基础
- JVM的基础知识
- JVM的内存区域
- JAVA方法运行的虚拟机栈
- 字节码指令参考:https://cloud.tencent.com/developer/article/1333540
正文
下面就通过代码创建一个简单的for循环、创建数组来研究一下字节码
一个一个来看吧。
for循环
java代码
public void method1(){
for (int i = 0; i < 1000; i++) {
}
}
javap -c 反汇编字节码
public void method1();
Code:
0: iconst_0 加载一个静态常量0到操作数栈
1: istore_1 将操作数栈栈顶的数值加载到局部变量表下标为1的位置上
2: iload_1 将局部变量表下标为1的数值加载到操作数栈中
3: sipush 1000 将常量1000加载到操作数栈
6: if_icmpge 15 比较栈顶两个int类型数值的大小 ,当前者 大于等于 后者时,跳转。(跳出循环)
9: iinc 1, 1 将局部变量表下标为1的数值自增1
12: goto 2 跳转到指令2继续执行(开启循环)
15: return
问题
这里这个if_icmpge 这个指令的解释有点争议,前者后者,到底是代码里的前者后者(i是前者,1000是后者),还是栈里数据的前者后者(这个就更分不清前后了,最好用栈顶栈底来说),让人搞不清。
经过我的研究,我将if_icmpge 的解释改为比较栈顶两个int类型数值的大小 ,当栈顶第二个数值(i) 大于等于 栈顶第一个数值(1000)时,跳转。(跳出循环),执行完此条命令栈顶的两个值会被清空
创建数组
java代码
public void method2(){
String[] array = {"0","1","2"};
}
javap -c 反汇编字节码
public void method2();
Code:
0: iconst_3 将一个常量3加载到操作数栈当中
1: anewarray #2 该指令首先从操作数栈中加载栈定数据(3),并创建一个大小为该数据的数组,并将该数组的对象引用放入操作数栈中
4: dup 拷贝一份栈顶的值,并将其压栈,例如栈顶的值刚开始为value,执行完为value,value
5: iconst_0 将数值为0的压入操作数栈中
6: ldc #3 将String "0"的字符串引用压入操作数栈当中
8: aastore 执行数组值存放,下面会解释
9: dup
10: iconst_1
11: ldc #4 // String 1
13: aastore
14: dup
15: iconst_2
16: ldc #5 // String 2
18: aastore
19: astore_1 将栈顶的数据(数组array的引用)加载到局部变量表下标为1的位置
20: return
关于aastore
可以参考:博客链接
第一个a表示数组中存放的数据类型,a是reference的意思。
第二个a表示array,表示这是一个数组操作。
store就是将元素存入数组了。
在使用这个aastore时,必须要先入栈数组引用,然后入栈下标index,然后入栈所需要存放的值。这是一种存放数组数据的标准。
可以看到真实的顺序是,先通过anewarray指令new出一个数组对象(array),并通过dup指令将数组array的引用拷贝了一份压入栈中,此时栈中有两个数组变量ints,然后入栈常量0,表示要操作数组array的下标,然后入栈String“0”的引用,表示要数组中要存放的数据。此时栈底到栈顶的顺序是:array(引用),array(引用),0,"0"。然后调用aastore,执行完清空栈,只留下一个栈底的ints的引用。然后继续执行。
网友评论