Java switch關(guān)鍵字原理及用法詳解
這篇文章主要介紹了Java中 switch關(guān)鍵原理及用法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
Switch語(yǔ)法
switch作為Java內(nèi)置關(guān)鍵字,卻在項(xiàng)目中真正使用的比較少。關(guān)于switch,還是有那么一些奧秘的。
要什么switch,我有if-else
確實(shí),項(xiàng)目中使用switch比較少的一個(gè)主要原因就在于它的作用能被if-else代替,況且switch對(duì)類型的限制,也阻礙了switch的進(jìn)一步使用。
先看看switch的語(yǔ)法:
switch(exp){
case exp1:
break;
case exp2:
break;
default:
break;
}
其中exp的類型限制為:byte ,short , int , char,及其包裝類,以及枚舉和String(JDK1.7)
為什么要有這些限制?
如果說(shuō),switch的功能和if-else的一模一樣,那么它存在的意義在哪里?
答案是:switch和if-else在設(shè)計(jì)的時(shí)候,是有一定的性能差別的。
看代碼:
public class Test {
public static void switchTest(int a) {
switch (a) {
case 1:
System.out.println("1");
break;
case 2:
System.out.println("2");
break;
default:
System.out.println("3");
break;
}
}
}
javap -c Test.class
結(jié)果如下:
public static void switchTest(int);
Code:
0: iload_0
1: lookupswitch { // 2
1: 28
2: 39
default: 50
}
...
這里面省略一些代碼。
可以發(fā)現(xiàn),switch是通過(guò)lookupswitch指令實(shí)現(xiàn)。那么lookupswitch指令是干嘛的呢?
在Java se8文檔中的描述可以大概知道:
switch可以被編譯為兩種指令
- lookupswitch:當(dāng)switch的case比較稀疏的時(shí)候,使用該指令對(duì)int值的case進(jìn)行一一比較,直至找到對(duì)應(yīng)的case(這里的查找,可以優(yōu)化為二分查找)
- tableswitch:當(dāng)switch的case比較密集的時(shí)候,使用case的值作為switch的下標(biāo),可以在時(shí)間復(fù)雜度為O(1)的情況下找到對(duì)應(yīng)的case(可以類比HashMap)
并且文檔中還有一段描述:
Java虛擬機(jī)的tableswitch和 lookupswitch指令僅對(duì)int數(shù)據(jù)有效。因?yàn)閷?duì) byte,char或或short值的操作在內(nèi)部被提升為int,所以對(duì)其switch表達(dá)式求值為其中一個(gè)類型進(jìn)行編譯,就好像它被計(jì)算為要鍵入一樣int。如果 chooseNear方法是使用type編寫的,則使用類型時(shí) short將生成相同的Java虛擬機(jī)指令int。其他數(shù)字類型必須縮小到類型int 以便在a中使用switch。
現(xiàn)在,我們應(yīng)該能夠明白,為什么switch關(guān)鍵字會(huì)有類型限制了,因?yàn)?switch所被翻譯的關(guān)鍵字是被限制為int類型的,至于為什么是int,我猜應(yīng)該是基于性能和實(shí)現(xiàn)的復(fù)雜度的考量吧。
int之外的類型
我們明白了byte,shor,char,int能被作為switch類型后,再看看枚舉和String
public static void switchTest(String a) {
switch (a) {
case "1":
System.out.println("1");
break;
case "2":
System.out.println("2");
break;
default:
System.out.println("3");
break;
}
}
編譯生成Test.class。拖入IDEA進(jìn)行反編譯得到如下代碼:
public static void switchTest(String a) {
byte var2 = -1;
switch(a.hashCode()) {
case 49:
if (a.equals("1")) {
var2 = 0;
}
break;
case 50:
if (a.equals("2")) {
var2 = 1;
}
}
switch(var2) {
case 0:
System.out.println("1");
break;
case 1:
System.out.println("2");
break;
default:
System.out.println("3");
}
}
可以看見,JDK7 所支持的String類型是通過(guò)獲取String的hashCode來(lái)進(jìn)行選擇的,也就是本質(zhì)上還是int.為什么String可以這樣干?這取決于String是一個(gè)不變類。
為了防止hash碰撞,代碼更加保險(xiǎn)的進(jìn)行了equals判斷。
再來(lái)看看Enum
public static void switchTest(Fruit a) {
switch (a) {
case Orange:
System.out.println("Orange");
break;
case Apple:
System.out.println("Apple");
break;
default:
System.out.println("Banana");
break;
}
}
編譯生成Test.class。拖入IDEA進(jìn)行反編譯得到如下代碼:
public static void switchTest(Fruit a) {
switch(1.$SwitchMap$com$dengchengchao$Fruit[a.ordinal()]) {
case 1:
System.out.println("Orange");
break;
case 2:
System.out.println("Apple");
break;
default:
System.out.println("Banana");
}
}
可以看到,枚舉支持switch更加簡(jiǎn)單,直接通過(guò)枚舉的順序即可作為相關(guān)case
總之:
switch的設(shè)計(jì)按道理來(lái)說(shuō),是比if-else要快的,但是在99.99%的情況下,他們性能差不多,除非case分支量巨大,但是在case分支過(guò)多的情況下,一般應(yīng)該考慮使用多態(tài)重構(gòu)了。
switch雖然支持byte,int,short,char,enum,String但是本質(zhì)上都是int,其他的只是編譯器幫你進(jìn)行了語(yǔ)法糖優(yōu)化而已。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 詳解java中if語(yǔ)句和switch的使用
- Java中switch的三種用法方式
- 淺談java switch如果case后面沒有break,會(huì)出現(xiàn)什么情況?
- java中的switch case語(yǔ)句使用詳解
- Java枚舉類型在switch語(yǔ)句正確使用方法詳解
- Java Switch對(duì)各類型支持實(shí)現(xiàn)原理
- Java switch使用原理及實(shí)例解析
- Java switch多值匹配操作詳解
- JAVA字符串類型switch的底層原理詳析
- Java switch 語(yǔ)句如何使用 String 參數(shù)
- Java實(shí)現(xiàn)轉(zhuǎn)跳不同系統(tǒng)使用枚舉加switch的方式示例
- java中switch選擇語(yǔ)句代碼詳解
- Java中Switch用法代碼示例
- Java基礎(chǔ)之switch分支結(jié)構(gòu)詳解
相關(guān)文章
如何在攔截器中獲取url路徑里面@PathVariable的參數(shù)值
這篇文章主要介紹了如何在攔截器中獲取url路徑里面@PathVariable的參數(shù)值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
Mybatis基于xml配置實(shí)現(xiàn)單表的增刪改查功能
這篇文章主要介紹了Mybatis基于xml配置實(shí)現(xiàn)單表的增刪改查,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04
Java Socket編程(四) 重復(fù)和并發(fā)服務(wù)器
Java Socket編程(四) 重復(fù)和并發(fā)服務(wù)器...2006-12-12
springboot連接redis并動(dòng)態(tài)切換database的實(shí)現(xiàn)方法
這篇文章主要介紹了springboot連接redis并動(dòng)態(tài)切換database,本文主為通過(guò)修改ConnectionFactory從而達(dá)到動(dòng)態(tài)切換database的效果,結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-03-03
JAVA實(shí)現(xiàn)將磁盤中所有空文件夾進(jìn)行刪除的代碼
這篇文章主要介紹了JAVA實(shí)現(xiàn)將磁盤中所有空文件夾進(jìn)行刪除的代碼,需要的朋友可以參考下2017-06-06
JavaSE經(jīng)典小練習(xí)項(xiàng)目之拷貝文件夾
文件拷貝是一個(gè)常見的任務(wù),無(wú)論是備份文件,還是將文件從一個(gè)位置復(fù)制到另一個(gè)位置,文件拷貝都是必不可少的,這篇文章主要給大家介紹了關(guān)于JavaSE經(jīng)典小練習(xí)項(xiàng)目之拷貝文件夾的相關(guān)資料,需要的朋友可以參考下2023-10-10

