Java 基礎語法 --- Switch
阿新 • • 發佈:2018-12-19
0x01 關鍵字Switch
在初學程式語言的時候,從C語言開始學起,所有的語言基本都會講到switch
關鍵字。他是一個用來進行分支判斷的關鍵字,和if
的作用類似,但是很多時候,使用switch
會更加的優雅並且更加的容易擴充套件。但是,我依稀的記得,switch
關鍵字並不支援String
型別(有待查驗)。
但是,不知道從JDK的哪個版本開始,switch
關鍵字開始支援String
了。很神奇。
0x02 Switch 基本實現
先來看一段簡單的程式碼:
class TestSwitchInteger {
public void methodA(int params) {
switch (params) {
case 1:
System.out.println("This is number 1.");
break;
case 2:
System.out.println("This is number 2.");
break;
default:
System.out.println("others number.");
break;
}
}
}
程式碼很清晰,methodA中,根據params的值來進行輸出。我們看一下編譯過後的程式碼是什麼樣子:
1: lookupswitch { // 2
1: 28
2: 39
default: 50
}
28: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
39: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
50: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
這個地方只列出了關鍵輸出,詳細內容請自行檢視,命令如下:
# javap -v TestSwitchInteger
可以看到,程式碼被翻譯成了lookupswitch, 當輸入引數為 1
接下來,我們看看String是怎麼實現的,先看原始碼:
public void methodA(String params) {
switch (params) {
case "a":
System.out.println("a");
break;
case "b":
System.out.println("b");
break;
default:
System.out.println("others");
break;
}
}
接下來,看看編譯過後的結構:
5: invokevirtual #2 // Method java/lang/String.hashCode:()I
8: lookupswitch { // 2
97: 36
98: 50
default: 61
}
36: aload_2
37: ldc #3 // String a
39: invokevirtual #4 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
42: ifeq 61
45: iconst_0
46: istore_3
47: goto 61
50: aload_2
51: ldc #5 // String b
53: invokevirtual #4 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
56: ifeq 61
59: iconst_1
60: istore_3
61: iload_3
62: lookupswitch { // 2
0: 88
1: 99
default: 110
}
88: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
91: ldc #3 // String a
93: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
96: goto 118
99: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
102: ldc #5 // String b
104: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
107: goto 118
110: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
113: ldc #8 // String others
115: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
可以看到,首先會執行 params.hashCode()
拿到一個int
值,然後去執行 int 的 switch方法,其中 97, 98 分別為a, b
的hashCode,然後會分別產生 0, 1 兩個基礎值,然後在執行一次 switch方法。翻譯成Java程式碼,就是如下情況:
public void methodA(String params) {
int a = -1;
switch (params.hashCode()) {
case "a".hashCode():
a = 0;
break;
case "b".hashCode():
a = 1;
default:
break;
}
switch (a) {
case 0:
System.out.println("a");
break;
case 1:
System.out.println("b");
break;
default:
System.out.println("others");
break;
}
}
0x03 思考
有些邏輯在語言層面不支援,我們可以從其它角度來考慮,說不定就能找到解決方案,就比如說上面這個,編譯的時候生成特殊的程式碼以完成對應的邏輯。在java中,還有一個和這個類似,那就是內部類呼叫外部類的private變數。有興趣的同學可以去研究一下。
在Android中也有一些庫使用了類似的方式,比如說 Butterknife, Dagger 2等。