A switch works with the byte, short, char, and int primitive data types. It also works with enumerated types, the String class, and a few special classes that wrap certain primitive types: Character, Byte, Short, and Integer
public class SwitchBasicTest {
private int switchByte(byte i) {
int ret;
switch (i) {
case 0:
ret = 10;
break;
case 1:
ret = 11;
break;
default:
ret = 0;
}
return ret;
}
private int switchChar(char i) {
int ret;
switch (i) {
case 0:
ret = 10;
break;
case 1:
ret = 11;
break;
case 'a':
ret = 20;
break;
case '写':
ret = 21;
break;
default:
ret = 0;
}
return ret;
}
}
复制代码
用 javap -v 或其他工具反编译 SwitchBasicTest.class
,本文使用 IDEA 插件 jclasslib Bytecode viewer
反编译得到 switchByte
方法的字节码:
0 iload_1
1 lookupswitch 2
0: 28 (+27)
1: 34 (+33)
default: 40 (+39)
28 bipush 10
30 istore_2
31 goto 42 (+11)
34 bipush 11
36 istore_2
37 goto 42 (+5)
40 iconst_0
41 istore_2
42 iload_2
43 ireturn
复制代码
switchChar
方法的字节码:
0 iload_1
1 lookupswitch 4
0: 44 (+43)
1: 50 (+49)
97: 56 (+55)
20889: 62 (+61)
default: 68 (+67)
44 bipush 10
46 istore_2
47 goto 70 (+23)
50 bipush 11
52 istore_2
53 goto 70 (+17)
56 bipush 20
58 istore_2
59 goto 70 (+11)
62 bipush 21
64 istore_2
65 goto 70 (+5)
68 iconst_0
69 istore_2
70 iload_2
71 ireturn
复制代码
可知对于 byte
等基础数据类型, switch
直接使用整型做比较
unicode intValue
public class SwitchBasicTest {
private int switchString(String i) {
int ret;
switch (i) {
case "0":
ret = 10;
break;
case "1":
ret = 11;
break;
case "a":
ret = 20;
break;
default:
ret = 0;
}
return ret;
}
}
复制代码
使用 IDEA 编辑器打开 .class 文件看到反编译代码:
public class SwitchBasicTest {
private int switchString(String i) {
byte var4 = -1;
switch(i.hashCode()) {
case 48:
if (i.equals("0")) {
var4 = 0;
}
break;
case 49:
if (i.equals("1")) {
var4 = 1;
}
break;
case 97:
if (i.equals("a")) {
var4 = 2;
}
}
byte ret;
switch(var4) {
case 0:
ret = 10;
break;
case 1:
ret = 11;
break;
case 2:
ret = 20;
break;
default:
ret = 0;
}
return ret;
}
}
复制代码
反编译得到 switchString
的字节码:
0 aload_1
1 astore_3
2 iconst_m1
3 istore 4
5 aload_3
6 invokevirtual #8 <java/lang/String.hashCode>
9 lookupswitch 3
48: 44 (+35)
49: 59 (+50)
97: 74 (+65)
default: 86 (+77)
44 aload_3
45 ldc #9 <0>
47 invokevirtual #10 <java/lang/String.equals>
50 ifeq 86 (+36)
53 iconst_0
54 istore 4
56 goto 86 (+30)
59 aload_3
60 ldc #11 <1>
62 invokevirtual #10 <java/lang/String.equals>
65 ifeq 86 (+21)
68 iconst_1
69 istore 4
71 goto 86 (+15)
74 aload_3
75 ldc #12 <a>
77 invokevirtual #10 <java/lang/String.equals>
80 ifeq 86 (+6)
83 iconst_2
84 istore 4
86 iload 4
88 tableswitch 0 to 2
0: 116 (+28)
1: 122 (+34)
2: 128 (+40)
default: 134 (+46)
116 bipush 10
118 istore_2
119 goto 136 (+17)
122 bipush 11
124 istore_2
125 goto 136 (+11)
128 bipush 20
130 istore_2
131 goto 136 (+5)
134 iconst_0
135 istore_2
136 iload_2
137 ireturn
复制代码
可以看到 switch
作用在 String
上最终拆分成两个针对整型 switch
语句,具体流程为:
equals
public enum SeasonEnum {
SPRING, SUMMER, AUTUMN, WINTER
}
public class SwitchEnumTest {
private static int testSpring(SeasonEnum seasonEnum) {
int ret;
switch (seasonEnum) {
case AUTUMN:
ret = 1;
break;
case SPRING:
ret = 2;
break;
case SUMMER:
ret = 3;
break;
case WINTER:
ret = 4;
break;
default:
ret = 5;
}
return ret;
}
}
复制代码
反编译得到 testSpring
方法的字节码:
0 getstatic #6 <xx/SwitchEnumTest$1.$SwitchMap$xx$enumt$SeasonEnum>
3 aload_0
4 invokevirtual #7 <xx/enumt/SeasonEnum.ordinal>
7 iaload
8 tableswitch 1 to 4 1: 40 (+32)
2: 45 (+37)
3: 50 (+42)
4: 55 (+47)
default: 60 (+52)
40 iconst_1
41 istore_1
42 goto 62 (+20)
45 iconst_2
46 istore_1
47 goto 62 (+15)
50 iconst_3
51 istore_1
52 goto 62 (+10)
55 iconst_4
56 istore_1
57 goto 62 (+5)
60 iconst_5
61 istore_1
62 iload_1
63 ireturn
复制代码
可以看到: 4 invokevirtual #7 <xx/enumt/SeasonEnum.ordinal>
即 switch
作用在枚举上时,调用枚举的 ordinal
方法 ,即最终还是 int
值比较
tableswitch
使用数组数据结构,通过下标可直接定位到跳转目标行 lookupswitch
维护了一个key-value的关系,通过逐个比较索引来查找匹配的待跳转的行数 tableswitch
比 lookupswitch
查找性能更佳 switch
语句中的 case
分支条件值比较稀疏时, tableswitch
指令的空间使用率偏低,这种情况下可能使用 lookupswitch
指令