說說Java中你不知道switch關鍵字

Switch語法

switch做爲Java內置關鍵字,卻在項目中真正使用的比較少。關於switch,仍是有那麼一些奧祕的。html

要什麼switch,我有if-else

確實,項目中使用switch比較少的一個主要緣由就在於它的做用能被if-else代替,何況switch對類型的限制,也阻礙了switch的進一步使用。java

先看看switch的語法:微信

switch(exp){
    case exp1:
        break;
    case exp2:
        break;
    default:
        break;
}

其中exp的類型限制爲:byte ,short , int , char,及其包裝類,以及枚舉和String(JDK1.7)oracle

爲何要有這些限制?

若是說,switch的功能和if-else的如出一轍,那麼它存在的意義在哪裏?jvm

答案是:switchif-else在設計的時候,是有必定的性能差異的。性能

看代碼:優化

public class Test {

    public static void switchTest(int a) {

        switch (a) {
            case 1:
                System.out.println("1");
                break;
            case 2:
                System.out.println("2");
                break;
            default:
                System.out.println("3");
                break;
        }
    }
}
javap  -c Test.class

結果以下:ui

public static void switchTest(int);
    Code:
       0: iload_0
       1: lookupswitch  { // 2
                     1: 28
                     2: 39
               default: 50
          }
          
    ...

這裏面省略一些代碼。翻譯

能夠發現,switch是經過lookupswitch指令實現。那麼lookupswitch指令是幹嗎的呢?設計

Java se8文檔中的描述能夠大概知道:

switch能夠被編譯爲兩種指令

  • lookupswitch:當switchcase比較稀疏的時候,使用該指令對int值的case進行一一比較,直至找到對應的case(這裏的查找,能夠優化爲二分查找)
  • tableswitch:當switchcase比較密集的時候,使用case的值做爲switch的下標,能夠在時間複雜度爲O(1)的狀況下找到對應的case(能夠類比HashMap)

而且文檔中還有一段描述:

Java虛擬機的tableswitchlookupswitch指令僅對int數據有效。由於對 bytechar或或short值的操做在內部被提高爲int,因此對其switch表達式求值爲其中一個類型進行編譯,就好像它被計算爲要鍵入同樣int。若是 chooseNear方法是使用type編寫的,則使用類型時 short將生成相同的Java虛擬機指令int。其餘數字類型必須縮小到類型int 以便在a中使用switch

如今,咱們應該可以明白,爲何switch關鍵字會有類型限制了,由於 switch所被翻譯的關鍵字是被限制爲int類型的,至於爲何是int,我猜應該是基於性能和實現的複雜度的考量吧。

int以外的類型

咱們明白了byte,shor,char,int能被做爲switch類型後,再看看枚舉和String

public static void switchTest(String a) {

        switch (a) {
            case "1":
                System.out.println("1");
                break;
            case "2":
                System.out.println("2");
                break;
            default:
                System.out.println("3");
                break;
        }
    }

編譯生成Test.class。拖入IDEA進行反編譯獲得以下代碼:

public static void switchTest(String a) {
        byte var2 = -1;
        switch(a.hashCode()) {
        case 49:
            if (a.equals("1")) {
                var2 = 0;
            }
            break;
        case 50:
            if (a.equals("2")) {
                var2 = 1;
            }
        }

        switch(var2) {
        case 0:
            System.out.println("1");
            break;
        case 1:
            System.out.println("2");
            break;
        default:
            System.out.println("3");
        }

    }

能夠看見,JDK7 所支持的String類型是經過獲取String的hashCode來進行選擇的,也就是本質上仍是int.爲何String能夠這樣幹?這取決於String是一個不變類。

爲了防止hash碰撞,代碼更加保險的進行了equals判斷。

再來看看Enum

public static void switchTest(Fruit a) {
    switch (a) {
        case Orange:
            System.out.println("Orange");
            break;
        case Apple:
            System.out.println("Apple");
            break;
        default:
            System.out.println("Banana");
            break;
    }

}

編譯生成Test.class。拖入IDEA進行反編譯獲得以下代碼:

public static void switchTest(Fruit a) {
        switch(1.$SwitchMap$com$dengchengchao$Fruit[a.ordinal()]) {
        case 1:
            System.out.println("Orange");
            break;
        case 2:
            System.out.println("Apple");
            break;
        default:
            System.out.println("Banana");
        }

    }

能夠看到,枚舉支持switch更加簡單,直接經過枚舉的順序便可做爲相關case

總之:

  • switch的設計按道理來講,是比if-else要快的,可是在99.99%的狀況下,他們性能差很少,除非case分支量巨大,可是在case分支過多的狀況下,通常應該考慮使用多態重構了。
  • switch雖然支持byte,int,short,char,enum,String可是本質上都是int,其餘的只是編譯器幫你進行了語法糖優化而已。

尊重勞動成果,轉載註明出處


若是以爲寫得不錯,歡迎關注微信公衆號:逸遊Java ,天天不定時發佈一些有關Java進階的文章,感謝關注

相關文章
相關標籤/搜索