深入了解JAVA技术(8)字节码指令有知道的嘛
2021/12/30 17:07:57
本文主要是介绍深入了解JAVA技术(8)字节码指令有知道的嘛,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
字节码指令:Java虚拟机的指令由一个字度长度的,代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随气候的零之多个代表此操作所需参数而构成。Java虚拟机采用面向操作数栈而不是寄存器的架构,大部分的指令都不包含操作数,只有一个操作码。
字节码指令集:是由多个字节码指令组成集,是一种指令集架构。
缺点:字节码指令集限制了Java虚拟机操作码的长度为一个字节,意味着指令集的操作嘛总数不可能超过256条,再一个class文件格式放弃了编译后代码的操作数长度对齐,如果虚拟机处理那些超过一个字节数据的时候,只能从字节中重建出具体数据的结构,可能导致损失一些性能。
优点:放弃了操作数长度对齐,就能省略很多填充和间隔符号。用一个字节来代表操作码,能获取短小精干的便宜代码。实现小数据量,高传输效率
字节码与数据类型
在Java虚拟机的指令集中,大多数指令都包含了其操作所对应的数据类相关信息。比如,iload指令用于从局部变量表中加载int型的数据到操作数栈中。fload指令是操作float类型的数据,这指令的操作在虚拟机内部可能会是同一段代码来实现,在class文件中拥有各自独立的操作码。
对于大部分与数据类型相关的字节码指令,他们操作码助记符中都有特殊字符来表示为那种数据类型服务:i代表int,l代表long,s代表short,b代表byte,c代表char,f代表float,d代表double,a代表reference。还有一些指令的助剂符中没有明确的指明操作类型的字母。arraylength指令:没有代表数据类型的特殊字符,但操作数永远只能是一个数组类型的对象。其中跳转指令goto与数据类型无关。
指令集并非完全独立的,有一些单独的指令可以用来将一些不支持类型转换成可被支持的类型
大部分指令都没有完全支持整数类型byte,char,short和布尔类型。编译器在编译期或者运行期将byte和short类型的数据转化成带符号扩展为相应的int类型数据,Boolean和char类型也是如此。因此,大多数对于Boolean,byte,short,char 类型数据的操作,本质上都是使用相应的int类型作为运算类型
加载和存储指令
加载和存储指令用于将数据在栈帧中的局部变量表和操作数栈之间来回传输
将一个局部变量加载到操作栈:ilaod,ilaod,llaod,llaod,flaod,flaod,dlaod,dlaod,alaod,alaod
将一个数值从操作数栈存储到局部变量表:istore,istore,lstore,lstore,fstore,fstore,dstore,dstore,astore,astore
将一个常量加载到操作数栈:bipush,sipushu,Idc,Idc_w,Idc2_w,aconst_null,iconst_ml,iconst,iconst,iconst,iconst
扩充局部变量表的访问索引的指令:wide。
上面有一部分是以尖括号结尾的指令助记符代表了一组指令
运算指令
运算或算术指令用于对两个操作栈上的值进行某种特定运算,并把结果重新存入到操作栈顶。
由于没有完全支持byte short char boolean 类型的算术指令,这些类型都是通过操做int类型的指令代替
运算指令 | int | long | float | double |
---|---|---|---|---|
加法指令 | iadd | ladd | fadd | dadd |
减法指令 | isub | lsub | fsub | dsub |
乘法指令 | imul | lmul | fmul | dmul |
除法指令 | idiv | ldiv | fdiv | ddiv |
求余指令 | irem | lrem | frem | drem |
取反指令 | ineg | lneg | fneg | dneg |
位移指令 | ishl | ishr | iushr | lshl |
按位或指令 | ior | lor | ||
按位与指令 | iand | land | ||
按位异或指令 | ixor | lxor | ||
局部变量自增指令 | iinc | |||
比较指令 | dcmpg | dcmpl | fcmpg | fcmpl |
类型转换指令
将两种不同的数值类型进行相互转换,实现用户代码中的显示类型转换操作
Java虚拟机直接支持不是显示的转换指令的宽化类型转换(小范围向大范围类型的安全转换):
int类型到long,float,double类型
long类型到float double 类型
float类型到double类型
处理窄化类型转换时,需要显示指令。
转换指令:i2b i2c i2s l2i f2i f2l d2i d2l d2f
缺点:可能会导致转换结果产生不同的正负号,不同的数量级情况,转化会失去精度。
浮点型窄化转换乘整数类型 ,注意一下规则:
浮点值是NaN 转化结果就是int或long的0
浮点值不是无穷大 向零舍入模式取整
如果doublle类型到float类型窄化转换 向最接近数舍入得到一个可以使用float 类型表示的数字 如果转换结果的绝对值太小无法使用float来表示,直接返回0。如果转换结果的绝对值太大无法使用float来表示,直接返回正负无穷大。
尽管数据窄化转换可能会发生上限溢出,下限溢出 精度丢失 但是 永远不可能抛出异常
对象创建与访问指令
类 实例和数组都是对象 但Java虚拟机对类实例和数组的创建与操作使用了不同的呃字节码指令。
指令如下:
创建类实例的指令:new
创建数组的指令:newarray anewarray multianewarray
访问类字段 (static 字段 ,类变量)和实例字段的指令:getfield putfield getstatic putstatic
把一个操作数栈的值存储到数组元素中的指令 : bastore castore sastore iastore fastore dastore aastore
把一个数组元素加载到操作数栈的指令:baload caload saload iaload faload daload aaload
取数组长度的指令:arraylength
检查类实例类型的指令:instanceof checkcast
操作数栈管理指令
Java虚拟机提供了一些用于直接操作操作数栈的指令:
将操作数栈的栈顶一个或两个元素出栈 pop pop2
复制栈顶一个或两个数值并将复制值或双份的复制值重新压入栈顶 dup dup2 dup_x1 dup2_x1 dup_x2 dup2_x2
将栈最顶端的两个值互换 swap
控制转移指令
能够让Java虚拟机有条件或无条件地从指定的位置指令而不是控制转移指令的下一条指令继续执行程序
指令如下:
条件分支:ifeq iflt ifle ifne ifgt ifge ifnull ifnonnull if_icmpeq if_icmpne if_icmplt if_icmpgt if_icmple if_icmpge ifacmpeq if_acmpne
复合条件分支:tablewitch lookupswitch
无条件分支:goto goto_w jsr jsr_w ret
在Java虚拟机中有专门的指令集用来处理int和reference类型的条件分支比较操作,为了可以无须明显标识一个是体制是否null 也有专门的指令用来检测null值,对于 boolean byte char short 条件分支比较操作,都是用int指令完成。对于 long float double 的条件分支比较操作,先执行相应类型的比较运算指令,运算指令会返回一个整型值到操作数栈中,再执行int类型的条件分支比较操作来完成整个分支跳转。因此 Java虚拟机提供的int类型的条件分支指令 最为丰富和强大
方法调用和返回指令
invokevirtual指令用于调用对象的实例方法,根据对象的实际类型进行分派
invokeinterface指令用于调用接口方法,它会在运行时搜索一个实现了这个接口方法的对象,找出合适的方法进行调用
invokespecial指令用于调用一些需要特殊处理的实例方法 包括实例初始化方法 私有方法 父类方法
invokestatic指令调用类方法 static方法
invokedynamic指令在运行时动态解析出调用点限定符所引用的 方法 执行该方法
方法调用指令与数据类型无关 方法返回指令 根据返回值的类型区分 包括 ireturn(当返回值是Boolean byte char short int )lreturn fretirn dreturn areturn 另外还有一条return指令提供声明为void方法 实例初始化方法 以及类和 接口的类初始化方法使用
异常处理指令
显示抛出异常的操作 由athrow指令 还有一些在Java虚拟机指令检测到异常状况时自动抛出
在Java虚拟机还可以用处理异常catch语句实现
同步指令
Java虚拟机支持方法级的同步和方法内部一段指令序列的同步 ,都是用管程来支持。
方法级的同步 虚拟机可以从方法常量池的方法表结构中的ACC_SYNCHRONIZED访问标志得知一个方法是否声明为同步方法。当方法调用时,调用指令将会检查方法的ACC_SYNCHRONIZED访问标识是否被设置,如果设置 执行线程先持有管程 后执行方法,方法完成时释放管程
方法内部同步 在方法执行期间 执行线程有管程 任何线程都无法获取到同一个管程 同步方法执行期间抛出异常 方法内部无法处理此异常 所持有的管程在异常抛到同步方法之外时自动释放
同步一段指令集序列 由synchronized 语句块来表示,Java虚拟机的指令集有monitorenter monitorexit 来支持synchronized 关键字的语义
在方法中调用过的每条monitorenter都对应着monitorexit指令,不管正常还是异常
这篇关于深入了解JAVA技术(8)字节码指令有知道的嘛的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南