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
指令