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语句的原因。

上一篇下一篇

猜你喜欢

热点阅读