条件判断指令
指令集合
- byte,short,char 都会按 int 比较,因为操作数栈都是 4 字节
- goto 用来进行跳转到指定行号的字节码
源码
package cn.knightzz.jvm.bytecode;
/**
* @author 王天赐
* @title: ConditionalJudgmentInstruction
* @projectName hm-jvm-codes
* @description: 条件判断指令
* @website <a href="http://knightzz.cn/">http://knightzz.cn/</a>
* @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a>
* @create: 2022-10-19 18:53
*/
public class ConditionalJudgmentInstruction {
public static void main(String[] args) {
int a = 0;
if (a == 0) {
a = 10;
} else {
a = 20;
}
}
}
字节码
$ javap -v ConditionalJudgmentInstruction.class
Classfile /F:/JavaCode/hm-jvm-codes/jvm-chapter-03/target/classes/cn/knightzz/jvm/bytecode/ConditionalJudgmentInstruction.class
Last modified 2022-10-19; size 561 bytes
MD5 checksum 4cb9364c4df2604d19885ce96894b9d9
Compiled from "ConditionalJudgmentInstruction.java"
public class cn.knightzz.jvm.bytecode.ConditionalJudgmentInstruction
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#20 // java/lang/Object."<init>":()V
#2 = Class #21 // cn/knightzz/jvm/bytecode/ConditionalJudgmentInstruction
#3 = Class #22 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 LocalVariableTable
#9 = Utf8 this
#10 = Utf8 Lcn/knightzz/jvm/bytecode/ConditionalJudgmentInstruction;
#11 = Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 = Utf8 args
#14 = Utf8 [Ljava/lang/String;
#15 = Utf8 a
#16 = Utf8 I
#17 = Utf8 StackMapTable
#18 = Utf8 SourceFile
#19 = Utf8 ConditionalJudgmentInstruction.java
#20 = NameAndType #4:#5 // "<init>":()V
#21 = Utf8 cn/knightzz/jvm/bytecode/ConditionalJudgmentInstruction
#22 = Utf8 java/lang/Object
{
public cn.knightzz.jvm.bytecode.ConditionalJudgmentInstruction();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 12: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcn/knightzz/jvm/bytecode/ConditionalJudgmentInstruction;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=2, args_size=1
0: iconst_0
1: istore_1
2: iload_1
3: ifne 12
6: bipush 10
8: istore_1
9: goto 15
12: bipush 20
14: istore_1
StackMapTable: number_of_entries = 2
frame_type = 252 /* append */
offset_delta = 12
locals = [ int ]
frame_type = 2 /* same */
}
SourceFile: "ConditionalJudgmentInstruction.java"
以上比较指令中没有 long,flfloat,double 的比较,那么它们要比较怎么办 ?
参考 : https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.lcmp
核心的字节码 :
0: iconst_0
1: istore_1
2: iload_1
3: ifne 12
6: bipush 10
8: istore_1
9: goto 15
12: bipush 20
14: istore_1
15: return
- ifne 判断是否不等于 0 , 如果为true 会直接跳转到
12: bipush 20
循环控制指令
源码
package cn.knightzz.jvm.bytecode;
/**
* @author 王天赐
* @title: CyclicControlInstruction
* @projectName hm-jvm-codes
* @description: 循环控制指令
* @website <a href="http://knightzz.cn/">http://knightzz.cn/</a>
* @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a>
* @create: 2022-10-19 19:11
*/
public class CyclicControlInstruction {
public static void main(String[] args) {
int a = 0;
while (a < 10) {
a++;
}
}
}
字节码
$ javap -v CyclicControlInstruction.class
Classfile /F:/JavaCode/hm-jvm-codes/jvm-chapter-03/target/classes/cn/knightzz/jvm/bytecode/CyclicControlInstruction.class
Last modified 2022-10-19; size 538 bytes
MD5 checksum 1d37128d3ea691714bb95fcb7f1edec9
Compiled from "CyclicControlInstruction.java"
public class cn.knightzz.jvm.bytecode.CyclicControlInstruction
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#20 // java/lang/Object."<init>":()V
#2 = Class #21 // cn/knightzz/jvm/bytecode/CyclicControlInstruction
#3 = Class #22 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 LocalVariableTable
#9 = Utf8 this
#10 = Utf8 Lcn/knightzz/jvm/bytecode/CyclicControlInstruction;
#11 = Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 = Utf8 args
#14 = Utf8 [Ljava/lang/String;
#15 = Utf8 a
#16 = Utf8 I
#17 = Utf8 StackMapTable
#18 = Utf8 SourceFile
#19 = Utf8 CyclicControlInstruction.java
#20 = NameAndType #4:#5 // "<init>":()V
#21 = Utf8 cn/knightzz/jvm/bytecode/CyclicControlInstruction
#22 = Utf8 java/lang/Object
{
public cn.knightzz.jvm.bytecode.CyclicControlInstruction();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 12: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcn/knightzz/jvm/bytecode/CyclicControlInstruction;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: iconst_0
1: istore_1
2: iload_1
3: bipush 10
5: if_icmpge 14
8: iinc 1, 1
11: goto 2
14: return
LineNumberTable:
line 16: 0
line 17: 2
line 18: 8
line 21: 14
LocalVariableTable:
Start Length Slot Name Signature
0 15 0 args [Ljava/lang/String;
2 13 1 a I
StackMapTable: number_of_entries = 2
frame_type = 252 /* append */
offset_delta = 2
locals = [ int ]
frame_type = 11 /* same */
}
SourceFile: "CyclicControlInstruction.java"
0: iconst_0
1: istore_1
2: iload_1
3: bipush 10
5: if_icmpge 14
8: iinc 1, 1
11: goto 2
14: return
- iconst_0 创建一个值为 0 的常量
- istore_1 赋值给 插槽1的变量 a
- iload_1 将a的值压入栈
- bipush 10 将10压入栈
- if_icmpge : 判断两个int是否 >= ==>
a >= 10
- 如果为true , 直接跳到 14:return
- 如果为false, iinc 1,1 => 插槽1中的元素a累加1
- goto 2 ==> 2: iload_1
其他的如 do while 和 for 其实都是类似的
练习-判断结果
源码
package cn.knightzz.jvm.bytecode;
/**
* @author 王天赐
* @title: JudgementResult
* @projectName hm-jvm-codes
* @description: 判断结果
* @website <a href="http://knightzz.cn/">http://knightzz.cn/</a>
* @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a>
* @create: 2022-10-19 19:22
*/
public class JudgementResult {
public static void main(String[] args) {
int i = 0;
int x = 0;
while (i < 10) {
x = x++;
i++;
}
System.out.println(x); // 结果是 0
}
}
字节码
// int i = 0
iconst_0
istore_1
// int x = 0
iconst_0
istore_2
iload_1
bipush 10
if_icmpge xxx
iload_2 // 将 0 加载进操作数栈
iinc 2,1 // 直接在局部变量表中累加
istore_2 // 将操作数栈中的元素 0 重新赋值到 x(slot_2)
iload_1
iinc 1,1
goto xxx
getstatic #x
invoke xx
最终的结果为0的原因是因为 :
- iload_2 ==> 将 0 加载进操作数栈
- iinc 2,1 ==> 直接在局部变量表中累加 , 此时 x = 1
- istore_2 // 将操作数栈中的元素 0 重新赋值到 x(slot_2) 此时 x = 0
赋值指令是从操作数栈复制到局部变量表中 , 而累加是 直接在局部变量表中累加
生成的字节码 :
0 iconst_0
1 istore_1
2 iconst_0
3 istore_2
4 iload_1
5 bipush 10
7 if_icmpge 21 (+14)
10 iload_2
11 iinc 2 by 1
14 istore_2
15 iinc 1 by 1
18 goto 4 (-14)
21 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
24 iload_2
25 invokevirtual #3 <java/io/PrintStream.println : (I)V>
28 return