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
intdata. Because operations onbyte,char, orshortvalues are internally promoted toint, aswitchwhose expression evaluates to one of those types is compiled as though it evaluated to typeint. If thechooseNearmethod 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 typeintfor 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
