switch
做爲Java內置關鍵字,卻在項目中真正使用的比較少。關於switch
,仍是有那麼一些奧祕的。html
確實,項目中使用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
答案是:switch
和if-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
:當switch
的case
比較稀疏的時候,使用該指令對int
值的case
進行一一比較,直至找到對應的case
(這裏的查找,能夠優化爲二分查找)tableswitch
:當switch
的case
比較密集的時候,使用case
的值做爲switch
的下標,能夠在時間複雜度爲O(1)的狀況下找到對應的case
(能夠類比HashMap)而且文檔中還有一段描述:
Java虛擬機的
tableswitch
和lookupswitch
指令僅對int
數據有效。由於對byte
,char
或或short
值的操做在內部被提高爲int
,因此對其switch
表達式求值爲其中一個類型進行編譯,就好像它被計算爲要鍵入同樣int
。若是chooseNear
方法是使用type編寫的,則使用類型時short
將生成相同的Java虛擬機指令int
。其餘數字類型必須縮小到類型int
以便在a中使用switch
。
如今,咱們應該可以明白,爲何switch
關鍵字會有類型限制了,由於 switch
所被翻譯的關鍵字是被限制爲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進階的文章,感謝關注