说说Java中你不知道switch关键字

Switch语法

switch做为Java内置关键字,却在项目中真正使用的比较少。关于switch,仍是有那么一些奥秘的。html

要什么switch,我有if-else

确实,项目中使用switch比较少的一个主要缘由就在于它的做用能被if-else代替,何况switch对类型的限制,也阻碍了switch的进一步使用。java

先看看switch的语法:微信

switch(exp){
    case exp1:
        break;
    case exp2:
        break;
    default:
        break;
}

其中exp的类型限制为:byte ,short , int , char,及其包装类,以及枚举和String(JDK1.7)oracle

为何要有这些限制?

若是说,switch的功能和if-else的如出一辙,那么它存在的意义在哪里?jvm

答案是:switchif-else在设计的时候,是有必定的性能差异的。性能

看代码:优化

public class Test {

    public static void switchTest(int a) {

        switch (a) {
            case 1:
                System.out.println("1");
                break;
            case 2:
                System.out.println("2");
                break;
            default:
                System.out.println("3");
                break;
        }
    }
}
javap  -c Test.class

结果以下:ui

public static void switchTest(int);
    Code:
       0: iload_0
       1: lookupswitch  { // 2
                     1: 28
                     2: 39
               default: 50
          }
          
    ...

这里面省略一些代码。翻译

能够发现,switch是经过lookupswitch指令实现。那么lookupswitch指令是干吗的呢?设计

Java se8文档中的描述能够大概知道:

switch能够被编译为两种指令

  • lookupswitch:当switchcase比较稀疏的时候,使用该指令对int值的case进行一一比较,直至找到对应的case(这里的查找,能够优化为二分查找)
  • tableswitch:当switchcase比较密集的时候,使用case的值做为switch的下标,能够在时间复杂度为O(1)的状况下找到对应的case(能够类比HashMap)

而且文档中还有一段描述:

Java虚拟机的tableswitchlookupswitch指令仅对int数据有效。由于对 bytechar或或short值的操做在内部被提高为int,因此对其switch表达式求值为其中一个类型进行编译,就好像它被计算为要键入同样int。若是 chooseNear方法是使用type编写的,则使用类型时 short将生成相同的Java虚拟机指令int。其余数字类型必须缩小到类型int 以便在a中使用switch

如今,咱们应该可以明白,为何switch关键字会有类型限制了,由于 switch所被翻译的关键字是被限制为int类型的,至于为何是int,我猜应该是基于性能和实现的复杂度的考量吧。

int以外的类型

咱们明白了byte,shor,char,int能被做为switch类型后,再看看枚举和String

public static void switchTest(String a) {

        switch (a) {
            case "1":
                System.out.println("1");
                break;
            case "2":
                System.out.println("2");
                break;
            default:
                System.out.println("3");
                break;
        }
    }

编译生成Test.class。拖入IDEA进行反编译获得以下代码:

public static void switchTest(String a) {
        byte var2 = -1;
        switch(a.hashCode()) {
        case 49:
            if (a.equals("1")) {
                var2 = 0;
            }
            break;
        case 50:
            if (a.equals("2")) {
                var2 = 1;
            }
        }

        switch(var2) {
        case 0:
            System.out.println("1");
            break;
        case 1:
            System.out.println("2");
            break;
        default:
            System.out.println("3");
        }

    }

能够看见,JDK7 所支持的String类型是经过获取String的hashCode来进行选择的,也就是本质上仍是int.为何String能够这样干?这取决于String是一个不变类。

为了防止hash碰撞,代码更加保险的进行了equals判断。

再来看看Enum

public static void switchTest(Fruit a) {
    switch (a) {
        case Orange:
            System.out.println("Orange");
            break;
        case Apple:
            System.out.println("Apple");
            break;
        default:
            System.out.println("Banana");
            break;
    }

}

编译生成Test.class。拖入IDEA进行反编译获得以下代码:

public static void switchTest(Fruit a) {
        switch(1.$SwitchMap$com$dengchengchao$Fruit[a.ordinal()]) {
        case 1:
            System.out.println("Orange");
            break;
        case 2:
            System.out.println("Apple");
            break;
        default:
            System.out.println("Banana");
        }

    }

能够看到,枚举支持switch更加简单,直接经过枚举的顺序便可做为相关case

总之:

  • switch的设计按道理来讲,是比if-else要快的,可是在99.99%的状况下,他们性能差很少,除非case分支量巨大,可是在case分支过多的状况下,通常应该考虑使用多态重构了。
  • switch虽然支持byte,int,short,char,enum,String可是本质上都是int,其余的只是编译器帮你进行了语法糖优化而已。

尊重劳动成果,转载注明出处


若是以为写得不错,欢迎关注微信公众号:逸游Java ,天天不定时发布一些有关Java进阶的文章,感谢关注

相关文章
相关标签/搜索