if-else 和 switch的区别
2021-03-08 本文已影响0人
Bug之王
一直以为if-else和switch除了形式上不太一样外效果应该是完全一样的,直到看到《Java编程的逻辑》的关于switch的内容时才发现还是有一点区别的。
如下if-else 代码:
public static void main(String[] args) {
int num1 = 2;
int num2;
if (num1 == 1) {
num2 = 1;
} else if (num1 == 2) {
num2 = 2;
} else {
num2 = 3;
}
System.out.println(num2);
}
通过javap -c命令查看字节码
public static void main(java.lang.String[]);
Code:
0: iconst_2 //常量2入操作数栈
1: istore_1 //操作数栈出栈,并赋值给第一个变量(num1)
2: iload_1 //第一个变量(num1)的值入操作数栈
3: iconst_1 //常量1入操作数栈
4: if_icmpne 12 //条件跳转:栈顶的两个值不相等则跳转到12行
7: iconst_1 //常量1入操作数栈
8: istore_2 //操作数栈出栈,并赋值给第二个变量(num2)
9: goto 24 //跳转到24行
12: iload_1 //第一个变量(num1)的值入操作数栈
13: iconst_2 //常量2入操作数栈
14: if_icmpne 22 //条件跳转:栈顶的两个值不相等则跳转到22行
17: iconst_2 //常量1人操作数栈
18: istore_2 //操作数栈出栈,并赋值给第二个变量(num2)
19: goto 24 //跳转到24行
22: iconst_3 //常量2入操作数栈
23: istore_2 //操作数栈出栈,并赋值给第二个变量(num2)
24: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
27: iload_2
28: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
31: return
0 ~ 1:给变量num1赋值
2 ~ 4:对应if行,当num1不等于2时,跳转到12行,也就是对应else if判断的那一行
7 ~ 8:给num2赋值,当条件跳转语句(第4行)没有跳转时执行
9:无条件跳转到24行,也就是if-else整体结束后的语句,这就是if-else语句只会执行一个子句的原因。
12 ~ 14:对应else-if判断,同2 ~ 4
17 ~ 18:给num2赋值,同7 ~ 8
19:无条件跳转,同9
22 ~ 23:给num2赋值,同7 ~ 8
通过上述代码可以看出if-else 语句主要是通过条件跳转指令和无条件跳转指令控制整个流程的,如果有多个子句,是需要多次判断,直到符合条件。
下面是相同效果的switch语句:
public static void main(String[] args) {
int num1 = 2;
int num2 = 3;
switch (num1) {
case 1:
num2 = 1;
break;
case 2:
num2 = 2;
break;
}
System.out.println(num2);
}
public static void main(java.lang.String[]);
Code:
0: iconst_2
1: istore_1
2: iload_1
3: lookupswitch { // 2
1: 28
2: 33
default: 38
}
28: iconst_1
29: istore_2
30: goto 40
33: iconst_2
34: istore_2
35: goto 40
38: iconst_3
39: istore_2
40: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
43: iload_2
44: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
47: return
可以看出字节码代码和if-else的完全不同,其通过lookupswitch(或者tableswitch)将条件集中在了一起,一个条件对应一个执行代码的行数,条件对应的执行逻辑在条件下边。tableswitch维护了一个数组,将switch语句传入的值作为下标找到要执行代码的行数;lookupswitch维护了一组key-value值,key排序,将switch语句传入的值作为目标值通过二分查找可以找到要执行的语句。可见对比if-else,性能上可以从O(n)提升到O(logn)或者O(1)。
另外,注意30和35行的跳转命令,对应我们的break语句,这就是为什么switch语句要写break语句的原因。