控制转移指令是 Java 字节码指令的一类,用于实现程序的条件和无条件跳转。常见的控制转移指令包括:
goto:无条件跳转到另一个指定的位置;
ifeq, ifne, iflt, ifle, ifgt, ifge:根据栈顶的值,判断是否满足条件,如果满足,则跳转到指定位置;
tableswitch:根据栈顶的值,跳转到不同的位置,类似于 switch-case 语句;
lookupswitch:根据栈顶的值,跳转到不同的位置,类似于 switch-case 语句,但是 case 的值不是连续的。
以下是一些控制转移指令的示例:
// ifeq:如果栈顶的值为 0,则跳转到 Label_1
ifeq Label_1
// ifne:如果栈顶的值不为 0,则跳转到 Label_1
ifne Label_1
// iflt:如果栈顶的值小于 0,则跳转到 Label_1
iflt Label_1
// ifge:如果栈顶的值大于等于 0,则跳转到 Label_1
ifge Label_1
// tableswitch:根据栈顶的值跳转到不同的位置
tableswitch 0 to 2: {
// case 0
Label_0
// case 1
Label_1
// case 2
Label_2
}
// lookupswitch:根据栈顶的值跳转到不同的位置
lookupswitch {
// case 0
0: Label_0
// case 1
1: Label_1
// case 2
2: Label_2
}
以下是一些控制转移指令的示例:
goto指令:
public static int foo(int x) {
if (x == 0) {
x = 1;
}
return x + 1;
}
反编译后的字节码:
public static int foo(int);
Code:
0: iload_0
1: ifne 6
4: iconst_1
5: istore_0
6: iload_0
7: iconst_1
8: iadd
9: ireturn
可以看到,如果x等于0,程序会跳转到第4条指令执行。
if指令:
public static void bar(int x) {
if (x > 0) {
System.out.println("x is positive");
} else {
System.out.println("x is non-positive");
}
}
反编译后的字节码:
public static void bar(int);
Code:
0: iload_0
1: ifgt 12
4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
7: ldc #3 // String x is non-positive
9: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
12: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
15: ldc #5 // String x is positive
17: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: return
可以看到,如果x大于0,程序会跳转到第12条指令执行,否则会跳转到第4条指令执行。
tableswitch指令:
public static void baz(int x) {
switch (x) {
case 0:
System.out.println("x is 0");
break;
case 1:
System.out.println("x is 1");
break;
case 2:
System.out.println("x is 2");
break;
default:
System.out.println("x is not 0, 1, or 2");
break;
}
}
反编译后的字节码:
public static void baz(int);
Code:
0: iload_0
1: tableswitch { // 0 to 2
0: 28
1: 34
2: 40
default: 46
}
28: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
31: goto 53
34: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
37: goto 53
40: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
43: goto 53
46: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
49: goto 53
52: return