更新時間:2020-11-17 17:51:37 來源:動力節(jié)點 瀏覽1091次
switch語句是Java控制語句里面非?;A的知識,也是老生常談的內(nèi)容。switch語句的語法比較簡單,相對也容易掌握。然而,大部分人卻是知其然,不知其所以然。本文將深入去探索switch語句的用法。
首先我們看看switch 語法的基本格式:
switch (表達式) {
case 常量表達式或枚舉常量:
語句;
break;
case 常量表達式或枚舉常量:
語句;
break;
......
default: 語句;
break;
}
switch 匹配的表達式可以是:
byte、short、char、int類型及 這4種類型的包裝類型;
枚舉類型;
String 類型;
case 匹配的表達式可以是:
常量表達式;
枚舉常量;
注意一點: case提供了switch表達式的入口地址,一旦switch表達式與某個case分支匹配,則從該分支的語句開始執(zhí)行,一直執(zhí)行下去,即其后的所有case分支的語句也會被執(zhí)行,直到遇到break語句。
看個例子體會一下:
public static void main(String[] args) {
String s = "a";
switch (s) {
case "a": //a分支
System.out.println("匹配成功1");
case "b": //b分支
System.out.println("匹配成功2");
case "c": //c分支
System.out.println("匹配成功3");
break;
case "d": //d分支
System.out.println("匹配成功4");
break;
default:
break;
}
}
運行結果:
匹配成功1
匹配成功2
匹配成功3
switch成功匹配了a分支,但a、b分支都沒有 break 語句,所以一直執(zhí)行a分支后的所有語句,直到遇到c分支的break語句才終止。
接下來我們來看看編譯器對 switch表達式的各種類型的處理:
盡管 switch 支持的類型擴充了幾個,但其實在底層中,swtich 只能支持4種基本類型,其他幾個類型是通過一些方式來間接處理的,下面便是講解編譯器對擴充類型的處理。
1、對包裝類的處理
對包裝類的處理是最簡單的 —— 拆箱??聪旅娴睦?,switch 比較的是包裝類 Byte 。
Byte b = 2;
switch (b) {
case 1:
System.out.println("匹配成功");
break;
case 2:
System.out.println("匹配成功");
break;
}
用jad反編譯一下這段代碼,得到的代碼如下:
Byte b = Byte.valueOf((byte)2);
switch(b.byteValue())
{
case 1: // '\001'
System.out.println("\u5339\u914D\u6210\u529F");
break;
case 2: // '\002'
System.out.println("\u5339\u914D\u6210\u529F");
break;
}
反編譯的代碼很簡單,底層的switch比較的是Byte通過(拆箱)方法byteValue()得到的byte值。順便說一下,這段反編譯代碼不僅揭開了 拆箱 的解析原理,也展示了 裝箱 的解析原理(第一句代碼);
2. 枚舉類型
為了簡單起見,直接采用JDK提供的枚舉類型的線程狀態(tài)類 Thread.state 類。
Thread.State state = Thread.State.RUNNABLE;
switch (state) {
case NEW:
System.out.println("線程處于創(chuàng)建狀態(tài)");
break;
case RUNNABLE:
System.out.println("線程處于可運行狀態(tài)");
break;
case TERMINATED:
System.out.println("線程結束");
break;
default:
break;
}
反編譯代碼:
Sex sex = Sex.MALE;
switch($SWITCH_TABLE$Test_2018_1_14$Sex()[sex.ordinal()])
{
case 1: // '\001'
System.out.println("sex:male");
break;
case 2: // '\002'
System.out.println("sex:female");
break;
}
從編譯代碼中發(fā)現(xiàn),編譯器對于枚舉類型的處理,是通過創(chuàng)建一個輔助數(shù)組來處理,這個數(shù)組是通過一個$SWITCH_TABLE$java$lang$Thread$State() 方法創(chuàng)建的,數(shù)組是一個int[]類型數(shù)組,數(shù)組很簡單,在每個枚舉常量的序號所對應的數(shù)組下標位置的賦一個值,按序號大小賦值,從1開始遞增。
3、 對String類型的處理
依舊是先看個例子,再查看這個例子反編譯代碼,了解編譯器的是如何解析的。
public static void main(String[] args) {
String s = "China";
switch (s) {
case "America":
System.out.println("匹配到美國");
break;
case "China":
System.out.println("匹配到中國");
break;
case "Japan":
System.out.println("匹配到日本");
default:
break;
}
}
反編譯得到的代碼:
public static void main(String args[])
{
String s = "China";
String s1;
switch((s1 = s).hashCode())
{
default:
break;
case 65078583:
if(s1.equals("China"))
System.out.println("\u5339\u914D\u5230\u4E2D\u56FD");
break;
case 71341030:
if(s1.equals("Japan"))
System.out.println("\u5339\u914D\u5230\u65E5\u672C");
break;
case 775550446:
if(s1.equals("America"))
System.out.println("\u5339\u914D\u5230\u7F8E\u56FD");
break;
}
}
從反編譯的代碼可以看出,switch 的String變量、case 的String常量都變成對應的字符串的 hash 值。也就是說,switch仍然沒有超出它的限制,只是通過使用 String對象的hash值來進行匹配比較,從而支持 String 類型。
通過上面的例子我們不難看出,底層的switch只能處理4個基本類型的值。其他三種類型需要通過其他方式間接處理,即轉成基本類型來處理。對枚舉類型的處理,是通過枚舉常量的序號及一個數(shù)組。而對字符串String的處理,是通過 String 的hash值。本文基本上已經(jīng)很全面的對switch語句的用法進行了介紹,這也是借鑒了本站的Java SE教程中的內(nèi)容,教程中對其他的Java控制語句的講解也很到位,感興趣的小伙伴可以前去觀看學習。