首先我們看下阿里泰山版的Java 開發手冊的規範:
1、在一個switch塊中,每個case通過continue/break/return 等來終止,要麼 註釋說明程序將接續執行哪一個case為止;在一個switch塊內,都必須包含一個default語句並且放在最後,即使什麼代碼都沒有。
說明:注意break是退出switch語句塊,而return是退出方法體;
2、當switch括號內的變量類型為String並且此變量為外部參數時,必須先進行null判斷;
反例:
<code>public
class
Demo
{public
static
void
main
(String[] args
) { methodDemo(null
); }public
static
void
methodDemo
(String param
){switch
(param){case
"nith"
: System.out
.println("it is nith!"
);case
"null"
: System.out
.println("It is null!"
);default
: System.out
.println("default"
); } } }/<code>
那麼上述的結果是什麼呢?
那為什麼是空指針呢?我們點擊switch是看不到源碼呢?那我們就從字節碼層次進行分析,為什麼是空指針?
<code>public
class
com.wy.demo.Demo
{
public
com.wy.demo.Demo();
Code:
0:
aload_0
1:
invokespecial
4:
return
public
static
void
main(java.lang.String[]);
Code:
0:
aconst_null
1:
invokestatic
4:
return
public
static
void
methodDemo(java.lang.String);
Code:
0:
aload_0
1:
astore_1
2:
iconst_m1
3:
istore_2
4:
aload_1
5:
invokevirtual
8:
lookupswitch
{
//
2
3381615:
36
3392903:
50
default:
61
}
36:
aload_1
37:
ldc
39:
invokevirtual
42:
ifeq
61
45:
iconst_0
46:
istore_2
47:
goto
61
50:
aload_1
51:
ldc
53:
invokevirtual
56:
ifeq
61
59:
iconst_1
60:
istore_2
61:
iload_2
62:
lookupswitch
{
//
2
0:
88
1:
96
default:
104
}
88:
getstatic
91:
ldc
93:
invokevirtual
96:
getstatic
99:
ldc
101:
invokevirtual
104:
getstatic
107:
ldc
109:
invokevirtual
112:
return
}
/<code>
- 0-3 :做了一些初始化操作,把入參param賦給局部變量表下標為2的變量
- 4-8 : 對入參param調用了hashCode函數,得到一個整型值。因此一般而言hash都是比較離散,所以沒有選擇tableswitch 而是用lookupswitch來作為switch case的實現
- 36 ~ 47:如果 hashCode 等於 "Java".hashCode() 會跳轉到這部分字節碼。首先把字符串進行真正意義上的 equals 比較,看是否相等,是否相等使用的是 ifeq 指令, ifeq 這個指令語義上有點繞,ifeq 的含義是ifeq 0則跳轉到對應字節碼行處,實際上是等於 false 跳轉。這裡如果相等則把 matchIndex 賦值為 0
- 61 ~ 96:進行最後的 case 分支執行。這一段比較好理解,不再繼續做分析。
從上面代碼看,如果我們傳入的是null,null的hashcode值就會包空指針;
結合上面字節碼解讀,我們可以推演出對應的java實現代碼:
<code>public
void
test
(String param
){ String tmpName = param;int
matchIndex =-1
;switch
(tmpName.hashCode()){case
3381615
:if
(tmpName.equals
("nith"
)) { matchIndex =1
; }break
;case
3392903
:if
(tmpName.equals
("null"
)) { matchIndex =0
; }break
;default
:break
; }switch
(matchIndex) {case
0
: System.out
.println("It is null!"
);case
1
: System.out
.println("It is null!"
);default
: System.out
.println("default"
); } }/<code>
所以我們最後總結一下:String的switch實現流程分為以下幾個步驟:
1、計算字符串的hashCode
2、使用 lookupswitch 對整型 hashCode 進行分支
3、對相同 hashCode 值的字符串進行最後的字符串匹配
4、執行 case 塊代碼