zoukankan      html  css  js  c++  java
  • 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标签没有放在最后,
    但它仍然是最后被匹配的。

  • 相关阅读:
    (3)C++复合类型
    (2)C++基本类型
    (7)js调试
    Oracle语句优先级
    oracle排序问题
    jsp四大对象
    postgresql时间加减计算
    全角空格,跟汉字一样宽
    bzoj1433 [ZJOI2009]假期的宿舍 最大流
    BZOJ 1264 AHOI2006 基因匹配Match 动态规划+树状数组
  • 原文地址:https://www.cnblogs.com/xiaomaohai/p/6157831.html
Copyright © 2011-2022 走看看