设为首页 加入收藏

TOP

《深入理解Java虚拟机》读书笔记:字节码指令简介(一)
2023-08-26 21:11:01 】 浏览:49
Tags:《深入理解 Java 简介

字节码指令简介

 

  Java虚拟机的指令由一个字节长度的、代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需参数(称为操作数,Operands)而构成。由于Java虚拟机采用面向操作数栈而不是寄存器的架构(这两种架构的区别和影响将在第8章中探讨),所以大多数的指令都不包含操作数,只有一个操作码。

  字节码指令集是一种具有鲜明特点、优劣势都很突出的指令集架构,由于限制了Java虚拟机操作码的长度为一个字节(即0~255),这意味着指令集的操作码总数不可能超过256条;又由于Class文件格式放弃了编译后代码的操作数长度对齐,这就意味着虚拟机处理那些超过一个字节数据的时候,不得不在运行时从字节中重建出具体数据的结构.

如果要将一个16位长度的无符号整数使用两个无符号字节存储起来(将它们命名为byte1和byte2),那它们的值应该是这样的:

(byte1 << 8) | byte2

  

  这种操作在某种程度上会导致解释执行字节码时损失一些性能。但这样做的优势也非常明显,放弃了操作数长度对齐[插图],就意味着可以省略很多填充和间隔符号;用一个字节来代表操作码,也是为了尽可能获得短小精干的编译代码。这种追求尽可能小数据量、高传输效率的设计是由Java语言设计之初面向网络、智能家电的技术背景所决定的,并一直沿用至今。

 

1 、字节码与数据类型

  在Java虚拟机的指令集中,大多数的指令都包含了其操作所对应的数据类型信息。对于大部分与数据类型相关的字节码指令,它们的操作码助记符中都有特殊的字符来表明专门为哪种数据类型服务:i代表对int类型的数据操作,l代表long,s代表short,b代表byte,c代表char,f代表float,d代表double,a代表reference。也有一些指令的助记符中没有明确地指明操作类型的字母,如arraylength指令,它没有代表数据类型的特殊字符,但操作数永远只能是一个数组类型的对象。还有另外一些指令,如无条件跳转指令goto则是与数据类型无关的。

表6-31 Java虚拟机指令集所支持的数据类型

2、加载和存储指令

  加载和存储指令用于将数据在栈帧中的局部变量表和操作数栈(见第2章关于内存区域的介绍)之间来回传输,这类指令包括如下内容。

(1)将一个局部变量加载到操作栈:iload、iload_<n>、lload、lload_<n>、fload、fload_<n>、dload、dload_<n>、aload、aload_<n>。

(2)将一个数值从操作数栈存储到局部变量表:istore、istore_<n>、lstore、lstore_<n>、fstore、fstore_<n>、dstore、dstore_<n>、astore、astore_<n>。

(3)将一个常量加载到操作数栈:bipush、sipush、ldc、ldc_w、ldc2_w、aconst_null、iconst_m1、iconst_<i>、lconst_<l>、fconst_<f>、dconst_<d>。

(4)扩充局部变量表的访问索引的指令:wide。

存储数据的操作数栈和局部变量表主要就是由加载和存储指令进行操作,除此之外,还有少量指令,如访问对象的字段或数组元素的指令也会向操作数栈传输数据。

 

3 、运算指令

  运算或算术指令用于对两个操作数栈上的值进行某种特定运算,并把结果重新存入到操作栈顶。大体上算术指令可以分为两种:对整型数据进行运算的指令与对浮点型数据进行运算的指令,无论是哪种算术指令,都使用Java虚拟机的数据类型,由于没有直接支持byte、short、char和boolean类型的算术指令,对于这类数据的运算,应使用操作int类型的指令代替。整数与浮点数的算术指令在溢出和被零除的时候也有各自不同的行为表现,所有的算术指令如下。

(1)加法指令:iadd、ladd、fadd、dadd。

(2)减法指令:isub、lsub、fsub、dsub。

(3)乘法指令:imul、lmul、fmul、dmul。

(4)除法指令:idiv、ldiv、fdiv、ddiv。

(5)求余指令:irem、lrem、frem、drem。

(5)取反指令:ineg、lneg、fneg、dneg。

(6)位移指令:ishl、ishr、iushr、lshl、lshr、lushr。

(7)按位或指令:ior、lor。

(8)按位与指令:iand、land。

(10)按位异或指令:ixor、lxor。

(11)局部变量自增指令:iinc。

(12)比较指令:dcmpg、dcmpl、fcmpg、fcmpl、lcmp。

 

4、类型转换指令

  可以将两种不同的数值类型进行相互转换,这些转换操作一般用于实现用户代码中的显式类型转换操作,或者用来处理本节开篇所提到的字节码指令集中数据类型相关指令无法与数据类型一一对应的问题。Java虚拟机直接支持(即转换时无需显式的转换指令)以下数值类型的宽化类型转换(Widening Numeric Conversions,即小范围类型向大范围类型的安全转换):

(1)int类型到long、float或者double类型。

(2)long类型到float、double类型。

(3)float类型到double类型。

 

  在将一个浮点值窄化转换为整数类型T(T限于int或long类型之一)的时候,将遵循以下转换规则:

(1)如果浮点值是NaN,那转换结果就是int或long类型的0。

(2)如果浮点值不是无穷大的话,浮点值使用IEEE 754的向零舍入模式取整,获得整数值v,如果v在目标类型T(int或long)的表示范围之内,那转换结果就是v。

(3)否则,将根据v的符号,转换为T所能表示的最大或者最小正数。

 

5、对象创建与访问指令

  虽然类实例和数组都是对象,但Java虚拟机对类实例和数组的创建与操作使用了不同的字节码指令(在第7章会讲到数组和普通类的类型创建过程是不同的)。对象创建后,就可以通过对象访问指令获取对象实例或者数组实例中的字段或者数组元素,这些指令如下。

(1)创建类实例的指令:new。

(2)创建数组的指令:newarray、anewarray、multianewarray。

(3)访问类字段(static字段,或者称为类变量)和实例字段(非static字段,或者称为实例变量)的指令:getfield、putfield、getstatic、putstatic。

(4)把一个数组元素加载到操作数栈的指令:baload、caload、saload、iaload、laload、faload、daload、aaload。

(5)将一个操作数栈的值存储到数组元素中的指令:bastore、castore、sastore、iastore、fastore、dastore、aastore。

(6)取数组

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇阿里EasyExcel快速导出demo 下一篇【狂神说Java】Java零基础学习笔..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目