📚《深入浅出JVM字节码》
《Java虚拟机字节码:从入门到实战》的开源版本。作者通过自己的实战经验,整合出一套适合新手的高效学习教程。归纳并提炼知识点,制定合理路线,帮助读者更快掌握核心技术。
数组的创建和访问也是我们编程中经常用到的。在java中,如果访问一个数组的索引超过数组的大小,会被虚拟机检测到,并抛出数组越界异常,这是因为在虚拟机执行访问数组的指令时,数组的大小已经是确定的,可以在执行指令之前检测索引是否超过数组大小。我们分基本数据类型数组、引用类型数组两种不同的数组,分别看下如何在字节码层面实现创建数组与访问数组元素。
基本数据类型的数组创建与访问案例代码如下。
public static void baseArray() {
int[] array = new int[2];
array[1] = 100;
int a = array[1];
}
使用javap命令输出baseArray方法的字节码如下。
public static void baseArray();
Code:
0: iconst_2
1: newarray int
3: astore_0
4: aload_0
5: iconst_1
6: bipush 100
8: iastore
9: aload_0
10: iconst_1
11: iaload
12: istore_1
13: return
偏移量为0和1的字节码指令完成数组的创建,iconst_2指令设置数组的大小为2,将立即数2放入操作数栈顶,newarray指令需要一个操作数,操作数占一个字节,如创建int类型的数组则操作数的值为10,创建long类型的数组则操作数为11等。
偏移量为4、5、6、8的这四条指令分别是将数组引用放入操作数栈顶、将访问数组的索引1放入操作数栈顶、将立即数100放入栈顶、最后iastore指令将栈顶int类型值100保存到int类型数组的索引为1的位置。偏移量为9、10、11这三条指令是读取int类型数组索引为1的元素放入操作数栈的栈顶,iaload指令将int类型数组指定索引位置处的元素放入操作数栈的栈顶。
iaload指令和iastore指令都不需要操作数。iastore指令执行之前,要求当前操作数栈必须存在int类型数组的引用、访问数组的索引、将要赋给数组元素的值,这三项是按顺序入栈的。iaload指令执行之前,要求当前操作数栈必须存在int类型数组的引用、访问数组的索引,按顺序入栈,返回值存放在操作数栈的栈顶。
访问基本数据类型数组的指令还有,对应long类型的laload和lastore指令,对应float类型的faload和fastore指令,对应double类型的daload和dastore指令,对应char类型的caload和castore指令,对应short类型的saload和sastore指令。
指令的操作码 | 指令的助记符 | 操作数 | 描述 |
---|---|---|---|
0x2E | iaload | 将int类型数组中指定索引的元素放入操作数栈顶 | |
0x2F | laload | 将long类型数组中指定索引的元素放入操作数栈顶 | |
0x30 | faload | 将float类型数组中指定索引的元素放入操作数栈顶 | |
0x31 | daload | 将double类型数组中指定索引的元素放入操作数栈顶 | |
0x34 | caload | 将char类型数组中指定索引的元素放入操作数栈顶 | |
0x35 | saload | 将short类型数组中指定索引的元素放入操作数栈顶 | |
0x33 | baload | 将boolean类型数组中指定索引的元素放入操作数栈顶 | |
0x4F | iastore | 将栈顶int类型值保存到指定int类型数组的指定索引处 | |
0x50 | lastore | 将栈顶long类型值保存到指定long类型数组的指定索引处 | |
0x51 | fastore | 将栈顶float类型值保存到指定int类型数组的指定索引处 | |
0x52 | dastore | 将栈顶double类型值保存到指定double类型数组的指定索引处 | |
0x55 | castore | 将栈顶char类型值保存到指定char类型数组的指定索引处 | |
0x56 | sastore | 将栈顶short类型值保存到指定short类型数组的指定索引处 | |
0x54 | bastore | 将栈顶boolean类型值保存到指定boolean类型数组的指定索引处 |
引用类型数组的创建与访问案例代码如下。
public static void objArray(){
User[] users = new User[2];
users[0] = new User();
users[1] = users[0];
}
使用javap命令输出objArray方法的字节码如下。
public static void objArray();
Code:
0: iconst_2
1: anewarray #2 // class com/wujiuye/asmbytecode/book/third/model/User
4: astore_0
5: aload_0
6: iconst_0
7: new #2 // class com/wujiuye/asmbytecode/book/third/model/User
10: dup
11: invokespecial #3 // Method com/wujiuye/asmbytecode/book/third/model/User."<init>":()V
14: aastore
15: aload_0
16: iconst_1
17: aload_0
18: iconst_0
19: aaload
20: aastore
21: return
与访问基本数据类型数组的逻辑差不多,创建数组使用的是anewarray指令,获取数组指定索引位置处的元素使用aaload指令,将对象的引用写到数组指定索引位置处使用aastore指令。
引用类型数组访问指令如下表所示。
指令的操作码 | 指令的助记符 | 操作数 | 描述 |
---|---|---|---|
0x2E | aaload | 将引用类型数组中指定索引的元素放入操作数栈顶 | |
0x53 | aastore | 将栈顶引用类型值保存到引用类型数组的指定索引位置处 |
创建数组的指令如下表所示。
指令的操作码 | 指令的助记符 | 操作数 | 描述 |
---|---|---|---|
0xBC | newarray | 创建基本数据类型的数组 | |
0x53 | anewarray | 创建引用类型的数组 |
访问数组的字节码指令还有获取数组一维长度的arrayleng指令,创建多维度的数组指令multinewarray指令。
发布于:2021 年 08 月 21 日
作者: 吴就业
链接: https://github.com/wujiuye/JVMByteCodeGitBook
来源: Github Pages 开源电子书《深入浅出JVM字节码》(《Java虚拟机字节码从入门到实战》的第二版),未经作者许可,禁止转载!
📚目录
订阅
订阅新文章发布通知吧,不错过精彩内容!
输入邮箱,提交后我们会给您发送一封邮件,您需点击邮件中的链接完成订阅设置。