• 说一说switch关键字的奥秘


    Switch语法

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

    要什么switch,我有if-else

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

    先看看switch的语法:

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

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

    为什么要有这些限制?

    如果说,switch的功能和if-else的一模一样,那么它存在的意义在哪里?

    答案是: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
    

    结果如下:

      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进阶的文章,感谢关注

  • 相关阅读:
    第四次作业:个人项目-小学四则运算 “软件”之初版
    随笔 | 阅读《构建之法》1-5章感想
    随笔 | 分布式版本控制系统Git的安装与使用
    随笔 | 对软件工程的一些感想
    为什么加载 JavaScript 使用 "src",CSS 使用 "href"?有其含义还是历史语法遗留?
    webstrom 添加一键open in browser
    sublime 代码段
    二.sublime配置 sublimecondeintel 分号后不要提示
    一.sublime配置 sublime 新建文档 默认html
    chrome使用
  • 原文地址:https://www.cnblogs.com/dengchengchao/p/11839910.html
Copyright © 2020-2023  润新知