一、管制转移指令概述
程序流程离不开条件管制,为了反对条件跳转,虚拟机提供了大量字节码指令,大体上能够分为
- 比拟指令、
- 条件跳转指令、
- 比拟条件跳转指令、
- 多条件分支跳转指令、
- 无条件跳转指令等。
后面咱们也提到过有比拟指令,指的是比拟两个栈顶元素的大小,并将比拟后果入栈
比拟指令有: dcmpg,dcmpl、fcmpg、fcmpl、lcmp
与后面解说的指令相似,首字符d示意double类型,f示意float,l示意long
对于double和float类型的数字,因为NaN的存在,各有两个版本的比拟指令
以float为例有fcmpg和fcmpl两个指令,区别在于在数字比拟时若遇到NaN值处理结果不同
指令dcmpl和dcmpg也是相似的,依据其命名能够揣测其含意,在此不再赘述
指令lcmp针对long型整数,因为long型整数没有NaN值,故无需筹备两套指令
举例比拟
================================
指令fcmpg和fcmpl都从栈中弹出两个操作数,并将它们做比拟
设栈顶的元素为v2,核顶顺位第2位的元素为v1
若v1=v2则压入0
若v1>v2则压入1
若v1<v2则压入1
两个指令的不同之处在于,如果遇到NaN值,fcmpg会压入1,而fcmpl会压入-1
二、管制转移指令的条件跳转指令解说
条件跳转指令通常和比拟指令联合应用。
在条件跳转指令执行前,个别能够先用比拟指令进行栈顶元素的筹备,而后进行条件跳转
条件跳转指令有: ifeq、iflt、ifle、ifne、ifgt、ifge、ifnull、ifnonnull
这些指令都接管两个字节的操作数,用于计算跳转的地位(16位符号整数作为以后地位的offset)
它们的对立含意为:弹出栈顶元素测试它是否满足某一条件,如果满足条件,则跳转到给定地位
具体指令阐明如下图所示:
留神:与后面运算规定统一
对于boolean、byte、char、short类型的条件分支比拟操作,都是应用int类型的比拟指令实现
对于long、 float、double类型的条件分支比拟操作,则会先执行相应类型的比拟运算指令,运算指令会返回一个整型值到操作数栈中,随后再执行int类型的条件分支比拟操作来实现整个分支跳转
因为比拟类型最终都会转为int类型,所以对于int类型的条件分支指令是最为丰盛和弱小的。
接下来咱们应用示例代码来领会领会条件跳转指令是怎么样的?
public class IfSwitchGotoTest { //1.条件跳转指令 public void compare1(){ int a = 0; if(a == 0){ a = 10; }else{ a = 20; } }}
接下来咱们编译代码应用插件查看具体的字节码是怎么样的?
接下来咱们剖析一下字节码指令,看看具体做了哪些事件?
接下来咱们再应用示例代码来领会领会条件跳转指令是怎么样的?
public class IfSwitchGotoTest { //1.条件跳转指令 public boolean compareNull(String str){ if( str == null){ return tlue; }else{ return false; } }}
接下来咱们编译代码应用插件查看具体的字节码是怎么样的?
接下来咱们下一个示例代码来领会不同的条件跳转指令是怎么样的?
public class IfSwitchGotoTest { //联合比拟指令 public void compare2() { float f1 = 9; f1oat f2 = 10; system.out.print1n(f1 < f2); }}
接下来咱们编译代码应用插件查看具体的字节码是怎么样的?
接下来咱们剖析一下字节码指令,看看具体做了哪些事件?
三、管制转移指令的比拟条件跳转指令解说
比拟条件跳转指令相似于比拟指令和条件跳转指令的结合体,它将比拟和跳转两个步骤合二为一
这类指令有:if_icmpeq、if_icmpne、if_icmpdt、if_icmpgt、if_icmple、if_icmpge、if_acmpeq、if_acmpne
其中指令助记符加上“if_”后,以字符“i”结尾的指令针对int型整数操作(也包含short和byte类型),以字符“a”结尾的指令示意对象援用的比拟。
这些指令都接管两个字节的操作数作为参数,用于计算跳转的地位。
同时在执行指令时
,栈顶须要筹备两个元素
进行比拟。指令执行实现后
,栈顶的这两个元素被清空,且没有任何数据入栈
。如果预没条件成立,则执行跳转
,否则,继续执行下一条语句。
接下来咱们再应用示例代码来领会领会比拟条件跳转指令是怎么样的?
public class IfSwitchGotoTest { public void ifCompare3(){ Object obj1 = new Object(); Object obj2 = new Object(); system.out.println(obj1 == obj2); system.out.println(obj1 != obj2); }}
接下来咱们编译代码应用插件查看具体的字节码是怎么样的?
四、管制转移指令的多条件分支跳转指令解说
多条件分支跳转指令是专为switch-case语句设计的,次要有tableswitch和lookupswitch。
从助记符上看,两者都是switch语句的实现,它们的区别:
tableswitch指令要求多个条件分支值是间断的,它外部只寄存起始值和终止值,以及若干个跳转偏移量,通过给定的操作数index,能够立刻定位到跳转偏移量地位,因而效率比拟高
lookupswitch指令外部寄存着各个离散的case-offset对,每次执行都要搜寻全副的case-offset对,找到匹配的case值
,并依据对应的offset计算跳转地址,因而效率较低
接下来咱们针对于多条件分支跳转指令的根本测试,请看以下示例代码
//3.多条件分支跳转public void swtich1(int select){ int num; switch(select){ case 1: num = 10; break; case 2: num = 20; break; case3: num = 30; break; default: num = 40; }}
接下来咱们编译该代码,看看swtich1办法的字节码是什么状况?
如果咱们的switch分支里的case并没有break完结的话,会是什么状况呢?看看示例代码
public void swtich1(int select){ int num; switch(select){ case 1: num = 10; break; case 2: num = 20; case3: num = 30; break; default: num = 40; }}
接下来咱们编译该代码,看看swtich1办法的字节码是什么状况?
接下来咱们应用下一个示例代码来领会多条件分支跳转指令,请看以下示例代码
public void swtich2(int select){ int num; switch(select){ case 100: num = 10; break; case 500: num = 20; break; case 208: num = 30; break; default: num = 40; }}
接下来咱们编译该代码,看看swtich2办法的字节码是什么状况?
咱们晓得在JDK7新个性是String类型,接下来应用咱们看看String类型的switch是怎么样
//jdk7新个性;引入string类型public void swtich3(String season){ switch(season){ case "SPRING" : break; case "SUMMER" : break; case "AUTUMN" : break; case "WINTER" : break; }}
接下来咱们编译该代码,看看swtich2办法的字节码是什么状况?
五、管制转移指令的无条件跳转指令解说
目前次要的无条件跳转指令为:goto
指令goto接管两个字节的操作数,独特组成一个带符号的整数,用于指定指令的偏移量,指令执行的目标就是跳转到偏移量给定的地位处
如果指令偏移量太大,超过双字节的带符号整数的范畴,则能够应用指令goto_w
,它和goto有雷同的作用,然而它接管4个字节的操作数,能够示意更大的地址范畴
指令jsr、jsr_w、ret尽管也是无条件跳转的,但次要用于 try-finally语句,且曾经被虚拟机逐步废除,故不在这里介绍这两个指令