JVM 指令03__对象的创建和访问指令
一、概述
Java 是面向对象的程序设计语言,虚拟机平台从字节码层面就对面向对象做了深层次的支持,有一系列的指令专门用于对象操作,这些指令可以进一步细分为创建指令、字段访问指令、数组操作指令、类型检查指令
二、创建指令
虽然类实例和数组都是对象,但是 Jvm 对类实例和数组的创建却使用了不同的指令
2.1、创建类对象的指令
new: 该指令接收一个操作数,这个操作数是指向常量池的索引,该索引表示的是要创建对象的类型,new 指令执行完成之后,将创建在堆内存中对象的内存空间地址值压入操作数栈中
newarray: 创建基本类型的一维数组
anewarray: 创建引用类型的一维数组
multianewarray: 创建多维数组
案例:
三、字段访问指令
对象创建完成之后,就可以通过对象访问指令来获取对象实例的字段或数组实例中的数组元素
访问静态字段: getstatic、putstatic
访问非静态字段: getfield、putfield
getxx 指令表示将 值/对象 压入操作数栈,putxx 指令表示将 值/对象 弹出操作数栈进行操作
四、数组操作指令
数组操作指令主要有 xastore 和 xaload
xastore: 将数组对象的内存地址值从局部变量表加载进入操作数栈
xaload: 将操作数栈中的值保存到堆空间数组对象的指定索引位置
数据类型 | 加载指令 | 存储指令 |
byte / boolean | baload | bastore |
short | saload | sastore |
char | caload | castore |
int | iaload | iastore |
long | laload | lastore |
float | faload | fastore |
double | daload | dastore |
reference | aaload | aastore |
案例
1 2 3 4 5 6 7 | public class Client { public static void main(String[] args) { int [] intArr = new int [ 3 ]; intArr[ 2 ] = 5 ; System.out.println(intArr[ 2 ]); } } |
对应字节码文件
1 2 3 4 5 6 7 8 9 10 11 12 13 | 0 iconst_3 1 newarray 10 ( int ) 3 astore_1 4 aload_1 5 iconst_2 6 iconst_5 7 iastore 8 getstatic # 2 <java/lang/System.out : Ljava/io/PrintStream;> 11 aload_1 12 iconst_2 13 iaload 14 invokevirtual # 3 <java/io/PrintStream.println : (I)V> 17 return |
指令 1、iconst_3: 将常量 3 压入操作数栈
指令 2、 newarray 10 (int): 将操作数 3 弹出操作数栈,在堆内存中为数组开辟出一块长度为 3 的空间,并且该数组元素的类型是 int,为数组进行默认初始化,完成之后将该数组空间的内存地址压入操作数栈
注 newarray 后面的 10 代表的是数组的类型,10 的类型就是 int 类型的数组,具体的官方 Jvm 指令定义类型如下
指令 3、astore_1: 将操作数栈顶的元素弹出,存入局部变量表下标为 1 的位置,该地址直接指向堆空间中数组的内存区域
指令 4、aload_1: 将局部变量表中下标为 1 的操作数压入操作数栈中
指令 5、iconst_2: 将常数 2 压入操作数栈中
指令 6、iconst_5: 将常数 5 压入操作数栈中
指令 7、iastore: 将操作数栈 5、2、0x3e86 弹出操作数栈,为数组第 2 个索引位置的元素进行显示赋值 5
通过 0x3e86 找到数组对象在堆空间的实际内存位置,2 作为数组下标索引,5 作为值为数组进行赋值操作
指令 8、getstatic: 通过符号引用 #2 在常量池中找到静态字段 System.out,并将其压入操作数栈中
指令 9、aload_1: 将局部变量表索引下标为 1 的操作数压入操作数栈
指令 10、iconst_2: 将常数 2 压入操作数栈
指令 11、iaload: 将操作数栈的栈顶操作数(2)和次栈顶操作数(0x3e86) 弹出操作数栈,通过 0x3e86 定位到数组在堆空间的实际位置,通过 2 定位到该数组索引为 2 的元素,将该元素的值压入操作数栈中
指令 12、invokevirtual #3: 通过符号引用找到常量池中对应的方法信息<println : (I)V>,main 方法栈帧中操作数弹出,接着在虚拟机栈中开辟 println 方法栈帧
输出结果 5 之后,println 方法栈帧出栈
main 方法执行完成之后 main 方法栈帧出操作数栈
堆空间的数组对象无任何引用指向,等待垃圾回收器回收
五、类型转换指令
类型检查指令主要有 instanceof 和 checkcast
instanceof: 判断对象是否是某一个类的实例,它会将判断后的结果压入操作数栈当中
checkcast: 检查类型是否可以进行强制类型转换,如果可以进行转换那么 checkcast 指令不会改变操作数栈,否则会抛出 ClassCastException
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2021-12-01 密码为什么要加盐
2021-12-01 Mybatis foreach 标签的使用
2021-12-01 Mybatis 多条件批量查询
2021-12-01 Java 获取昨天、前天时间
2020-12-01 Docker 启动 Error response from daemon: Cannot start container xxx 错误
2020-12-01 Springboot 2.x 整合 Mybatis