switch 支持的類型
在 Java 語言規范里中,有說明 switch 支持的類型有:char、byte、short、int、Character、Byte、Short、Integer、String、enum。
為什么不支持 long ?
為什么只支持上面幾種?int、String 都可以,為什么不支持 long ?
原因就是 switch 對應的 JVM 字節碼 lookupswitch、tableswitch 指令只支持 int 類型。
下面是 JVM 規范中的說明(https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-3.html#jvms-3.10):
The Java Virtual Machine's tableswitch and lookupswitch instructions operate only on
int
data. Because operations onbyte
,char
, orshort
values are internally promoted toint
, aswitch
whose expression evaluates to one of those types is compiled as though it evaluated to typeint
. If thechooseNear
method had been written using typeshort
, the same Java Virtual Machine instructions would have been generated as when using typeint
. Other numeric types must be narrowed to typeint
for use in aswitch
.
byte、char、short 類型在編譯期默認提升為 int,並使用 int 類型的字節碼指令。所以對這些類型使用 switch,其實跟 int 類型是一樣的。
為什么可以支持 String?
switch 支持 String 其實就是語法糖。編譯器會根據字符串的 hashCode
來處理。
例:
String a = "aa";
switch (a) {
case "aa":
System.out.println("111");
break;
case "AaAa":
System.out.println("222");
break;
case "AaBB":
System.out.println("333");
break;
}
反編譯后:
String var1 = "aa";
byte var3 = -1;
switch(var1.hashCode()) { // 第一個switch,根據hashCode計算第二個switch內的位置
case 3104:
if (var1.equals("aa")) {
var3 = 0;
}
break;
case 2031744:
if (var1.equals("AaBB")) {
var3 = 2;
} else if (var1.equals("AaAa")) {
var3 = 1;
}
}
switch(var3) { // 第二個switch,執行原switch的邏輯
case 0:
System.out.println("111");
break;
case 1:
System.out.println("222");
break;
case 2:
System.out.println("333");
}
可以發現,會先根據 hashCode 找出原始 switch 內的位置,再執行原代碼邏輯。
為什么用兩個 switch ?
就是為了減少編譯器的工作。
比如 switch 內有的 case 不寫 break 等復雜情況,如果想直接根據 hashCode + equals 來只生成一個 switch,編譯器就需要考慮各種情況。
所以目前編譯器只做位置映射,第二部分直接按原 switch 來生成了。
關於 lookupswitch、tableswitch 可參考:你所不知道的Java之Switch