目前Java中switch语句支持的数据类型包括:byte、short、int、char、String以及Enum,那么switch语句是如何实现的呢?
一、switch对整型的支持
public void switchInt(int value) {
switch (value) {
case 1:
System.out.println("1");
break;
case 2:
System.out.println("2");
break;
default:
System.out.println("Error value");
break;
}
}
使用javap -c进行反编译可以看到:
public void switchInt(int);
Code:
0: iload_1
1: lookupswitch { // 2
1: 28
2: 39
default: 50
}
28: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
31: ldc #14 // String 1
33: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
36: goto 58
39: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
42: ldc #15 // String 2
44: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
47: goto 58
50: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
53: ldc #16 // String Error value
55: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
58: return
可以看到,switch对整型的支持是直接比较int的值(如果换做byte和short,反编译后是一样的)。
二、switch对char的支持
public void switchChar(char value) {
switch (value) {
case 'a':
System.out.println("a");
break;
case 'b':
System.out.println("b");
break;
default:
System.out.println("Error value");
break;
}
}
使用javap -c进行反编译可以看到:
public void switchChar(char);
Code:
0: iload_1
1: lookupswitch { // 2
97: 28
98: 39
default: 50
}
28: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
31: ldc #17 // String a
33: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
36: goto 58
39: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
42: ldc #18 // String b
44: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
47: goto 58
50: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
53: ldc #16 // String Error value
55: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
58: return
可以看到,switch对char的支持是将char转换成int值,再做比较的。
三、switch对字符串的支持
public void switchString(String str) {
switch (str) {
case "hello":
System.out.println("hello");
break;
case "welcome":
System.out.println("welcome");
break;
default:
System.out.println("Error value");
break;
}
}
使用javap -c进行反编译可以看到:
public void switchString(java.lang.String);
Code:
0: aload_1
1: astore_2
2: iconst_m1
3: istore_3
4: aload_2
5: invokevirtual #19 // Method java/lang/String.hashCode:()I
8: lookupswitch { // 2
99162322: 36
1233099618: 50
default: 61
}
36: aload_2
37: ldc #20 // String hello
39: invokevirtual #21 // 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 #22 // String welcome
53: invokevirtual #21 // 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 #8 // Field java/lang/System.out:Ljava/io/PrintStream;
91: ldc #20 // String hello
93: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
96: goto 118
99: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
102: ldc #22 // String welcome
104: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
107: goto 118
110: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
113: ldc #16 // String Error value
115: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
118: return
可以看到,switch对字符串的支持是先比较hashCode,再用equals做校验,最后用得到的值再switch一次。
四、switch对枚举类型的支持
public void switchEnum(State state) {
switch (state) {
case Start:
System.out.println("Start");
break;
case InProcessing:
System.out.println("InProcessing");
break;
case Finished:
System.out.println("Finished");
break;
default:
System.out.println("Error state");
break;
}
}
使用javap -c进行反编译可以看到:
public void switchEnum(pers.wukong.onestep.State);
Code:
0: getstatic #6 // Field pers/wukong/onestep/Test$1.$SwitchMap$pers$wukong$onestep$State:[I
3: aload_1
4: invokevirtual #7 // Method pers/wukong/onestep/State.ordinal:()I
7: iaload
8: tableswitch { // 1 to 3
1: 36
2: 47
3: 58
default: 69
}
36: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
39: ldc #9 // String Start
41: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
44: goto 77
47: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
50: ldc #11 // String InProcessing
52: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
55: goto 77
58: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
61: ldc #12 // String Finished
63: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
66: goto 77
69: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
72: ldc #13 // String Error state
74: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
77: return
switch对枚举类型的支持和我预想的不一样,它是维护了一个SwitchMap,枚举的ordinal()方法的返回值作为Key,value是从1开始递增的。switch比较的就是这个value值。
总结
switch其实都是通过int来实现的,不同的是,各种数据类型转换int的方式是不一样的。