Java温故知新之深入Switch语句


一、基本用法

switch的case语句可以处理int,short,byte,char类型的值,但是不能处理long,String等类型。
因为short,byte,char都会转换成int进行处理,这一点也可以从生成的字节码看出。
char a = 'e'; switch (a) { case 'c': System.out.println("In case c"); break; case 'd': System.out.println("In case d"); break; default: System.out.println("In default"); break; case 'e': System.out.println("In case e"); break; }

0: bipush 101
2: istore_1
3: iload_1
4: tableswitch{ //99 to 101
99: 32;
100: 43;
101: 65;
default: 54 }

生成的字节码始终为bipush或iconst(小于5的整数),用于将整数压入栈。


二、新特性

在JDK 5中加入的枚举Enum类型也是可以作为case值的。
Type t = Type.C; switch (t) { case A: System.out.println("In case A"); break; case B: System.out.println("In case B"); break; default: System.out.println("In default"); break; case C: System.out.println("In case C"); break; }

0: getstatic #18; //Field com/cdai/jdk/Type.C:Lcom/cdai/jdk/Type;
3: astore_1
4: invokestatic #24; //Method $SWITCH_TABLE$com$cdai$jdk$Type:()[I
7: aload_1
8: invokevirtual #27; //Method com/cdai/jdk/Type.ordinal:()I
11: iaload
12: tableswitch{ //1 to 3
1: 40;
2: 51;
3: 73;
default: 62 }

从字节码可以看出,对于枚举类型也是调用它的ordinal方法转成整型后进行switch匹配的。

在JDK 7中,又加入了对String类型的支持,从此不用再写If-Else来判断字符串了。


三、两种字节码

switch语句有两种编译结果:

当case中的值连续时,编译成tableswitch,解释执行时从table数组根据case值计算下标来取值,从数组中取到的
便是要跳转的行数。
int a = 1; switch (a) { case 2: System.out.println("In case 2"); break; case 3: System.out.println("In case 3"); break; default: System.out.println("In default"); break; case 1: System.out.println("In case 1"); break; }

0: iconst_1
1: istore_1
2: iload_1
3:tableswitch{ //1 to 3
1: 61;
2: 28;
3: 39;
default: 50 }

28: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
31: ldc #22; //String In case 2
33: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
36: goto 69
39: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
42: ldc #30; //String In case 3
44: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
47: goto 69
50: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
53: ldc #32; //String In default
55: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
58: goto 69
61: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
64: ldc #34; //String In case 1
66: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V


当case中的值不连续时,编译成lookupswitch,解释执行时需要从头到尾遍历找到case对应的代码行。
因为case对应的值不是连续的,如果仍然用表来保存case对应的行号,会浪费大量空间。
int a = 10; switch (a) { case 2: System.out.println("In case 2"); break; case 3: System.out.println("In case 3"); break; default: System.out.println("In default"); break; case 10: System.out.println("In case 10"); break; }

0: bipush 10
2: istore_1
3: iload_1
4: lookupswitch{ //3
2: 40;
3: 51;
10: 73;
default: 62 }

40: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
43: ldc #22; //String In case 2
45: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
48: goto 81
51: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
54: ldc #30; //String In case 3
56: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
59: goto 81
62: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
65: ldc #32; //String In default
67: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
70: goto 81
73: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
76: ldc #34; //String In case 10
78: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

由此可以看出,这两种编译结果是编译器在考虑空间占用情况下,对代码效率进行的优化。

另外需要注意一点,就是不管是tableswitch还是lookupswitch,default标签都放在最后进行匹配,
但下面各个case和default语句块的顺序是与源代码相同的。所以尽管default标签没有放在最后,
但它仍然是最后被匹配的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值