Java 中 switch 語(yǔ)句支持字符串類型的歷史和原理
想象一下這個(gè)場(chǎng)景:你正在寫(xiě)一個(gè)水果識(shí)別的程序,用戶輸入「蘋(píng)果」就要執(zhí)行特定邏輯。在 Java 7 之前,你只能這樣寫(xiě):
if (fruit.equals("蘋(píng)果")) {
// 處理蘋(píng)果
} else if (fruit.equals("香蕉")) {
// 處理香蕉
} else {
//... 其他水果
}這種寫(xiě)法就像超市收銀員每次結(jié)賬都要拆開(kāi)包裹檢查商品,而 Java 7 之后的字符串 switch 相當(dāng)于給每個(gè)商品貼了快速識(shí)別條形碼-程序員寫(xiě)代碼更優(yōu)雅。
以前為什么不能用字符串?
早期的 Java(Java 7 以前)switch 只能處理數(shù)字類數(shù)據(jù)(比如 int、char),因?yàn)檫@些類型底層可以直接用數(shù)字比對(duì),簡(jiǎn)單快速。而字符串是復(fù)雜對(duì)象,直接逐個(gè)字符對(duì)比太費(fèi)時(shí)間,所以那時(shí)候只能用 if-else 處理字符串分支。
字符串的“身份證”——哈希碼(Hash Code)
每個(gè)字符串都有個(gè)唯一的哈希碼(可以理解成根據(jù)內(nèi)容用數(shù)學(xué)公式算出來(lái)的身份證號(hào)):
- ? 比如 "蘋(píng)果" 的哈希碼是 12345,"香蕉" 的哈希碼是 67890
- ? 關(guān)鍵特性:內(nèi)容相同的字符串哈希碼一定相同,不同內(nèi)容大概率不同(極小概率重復(fù),叫“哈希碰撞”)
switch 字符串操作
1. 存身份證號(hào)編譯器會(huì)把所有 case 后的字符串(比如 "蘋(píng)果"、"香蕉")的哈希碼存進(jìn)一個(gè)數(shù)組里。
2. 先比身份證號(hào)運(yùn)行到 switch 時(shí),先計(jì)算輸入字符串的哈希碼(比如用戶輸入 "蘋(píng)果",算出 12345),然后去數(shù)組里快速匹配。
3. 再驗(yàn)真身(防冒牌貨)哈希碼匹配后,還要用 equals() 方法確認(rèn)字符串內(nèi)容是否真的相同(防止極小概率的哈希碰撞)。
從本質(zhì)來(lái)講,switch 對(duì)字符串的支持,其實(shí)也是 int 類型值的匹配。
舉個(gè)栗子 ??
String fruit = "蘋(píng)果";
switch(fruit) {
case "蘋(píng)果":
System.out.println("紅富士");
break;
case "香蕉":
System.out.println("芝麻蕉");
break;
default:
System.out.println("不認(rèn)識(shí)");
}在這個(gè)例子中,編譯器會(huì)先計(jì)算 "蘋(píng)果" 和 "香蕉" 的哈希碼,然后在運(yùn)行時(shí)計(jì)算 fruit 的哈希碼。如果 fruit 的哈希碼和 "蘋(píng)果" 的哈希碼匹配,它會(huì)再用 equals 方法確認(rèn) fruit 是否真的是 "蘋(píng)果"。如果是,就輸出 "紅富士"。
編譯器的優(yōu)化
為了讓 switch 語(yǔ)句更高效,編譯器還會(huì)做一些優(yōu)化。比如,如果 case 標(biāo)簽不多,編譯器可能會(huì)直接用一系列的 if-else 語(yǔ)句來(lái)代替 switch 語(yǔ)句。這樣做可以減少 hashCode 計(jì)算和 equals 方法調(diào)用的次數(shù),從而提高性能。
性能考慮
雖然字符串類型的 switch 語(yǔ)句很方便,但它畢竟需要計(jì)算哈希碼 hashCode 和調(diào)用 equals 方法,所以在性能要求非常高的場(chǎng)合,可能不如用整數(shù)類型或枚舉類型來(lái)得快。比如,在一些對(duì)速度要求極高的游戲中,開(kāi)發(fā)者可能會(huì)選擇用整數(shù)或枚舉類型來(lái)避免額外的性能開(kāi)銷。switch 語(yǔ)句讓編程變得更加靈活,但也需要注意它的性能特點(diǎn),合理選擇適用的場(chǎng)景。





















