说说Java中你不知道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的一模一样,那么它存在的意义在哪里?
答案是:switch和if-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:当- switch的- case比较稀疏的时候,使用该指令对- int值的- case进行一一比较,直至找到对应的- case(这里的查找,可以优化为二分查找)
- tableswitch:当- switch的- case比较密集的时候,使用- case的值作为- switch的下标,可以在时间复杂度为O(1)的情况下找到对应的- case(可以类比HashMap)
并且文档中还有一段描述:
Java虚拟机的
tableswitch和lookupswitch指令仅对int数据有效。因为对byte,char或或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进阶的文章,感谢关注

说说Java中你不知道switch关键字的更多相关文章
- Java中的50个关键字
		form:http://blog.csdn.net/luoweifu/article/details/6776240 Java中的50个关键字 关键字也称为保留字,是指java语言中规定了特定含义的标 ... 
- Java中的两个关键字——super、this
		Java中的两个关键字——super.this 神话丿小王子的博客主页 一.super super 是java中方的一个关键字,用它可以引用父类中的成员: super可用于访问父类中定义的属性 sup ... 
- 【每周一译】愚蠢的指标:Java中使用最多的关键字
		此翻译纯属个人爱好,由于水平所限,翻译质量可能较低.网络上可能存在其它翻译版本,原文地址:http://blog.jooq.org/2013/08/26/silly-metrics-the-most- ... 
- Java中的标识符和关键字
		1.标识符 含义:标识符用于给程序中的类.变量.方法命名的符号. 组成:数字(0-9).字母(a-z)(A-Z).下划线(_).美元符号$. 命名规则:1.数字不能够作为命名符号的开头 2.不能够使用 ... 
- 1.3 Java中的标识符和关键字
		1.标识符 含义:标识符用于给程序中的类.变量.方法命名的符号. 组成:数字(0-9).字母(a-z)(A-Z).下划线(_).美元符号$. 命名规则:1.数字不能够作为命名符号的开头 2.不能够使用 ... 
- java中的标识符、关键字、保留字
		Java中关键字(keyword)和保留字(reservedword) Keyword :Java的关键字对java的编译器有特殊的意义,他们用来表示一种数据类型,或者表示程序的结构等. Reserv ... 
- Java中this、static关键字的内存图解
		Java中的关键字有很多,abstract default goto* null switch boolean do if package nchronzed break dou ... 
- java中this和super关键字的使用
		这几天看到类在继承时会用到this和super,这里就做了一点总结,与各位共同交流,有错误请各位指正~ this this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针. this ... 
- Java中需要知道的关键字
		Java中有一些或常用,或不常用,但却不得不知关键字,本篇文章将讨论这些关键字的作用. transient transient关键字可能用的不是那么频繁,但却是一个很重要的关键字,它的作用是在对象序列 ... 
随机推荐
- Kafka 学习笔记之 架构
			Kafka的概念: 1. AMQP协议 Advanced Message Queuing Protocol (高级消息队列协议) The Advanced Message Queuing Protoc ... 
- java的日期时间处理(待更新)
			1. /* * 将时间转换为时间戳 */ public static String dateToStamp(String s) throws ParseExcepti ... 
- PHP生成唯一ID的方法
			PHP自带生成唯一id的函数:uniqid() 它是基于当前时间微秒数的 用法如下: echo uniqid(); //13位的字符串 echo uniqid("php_"); / ... 
- Java8新特性时间日期库DateTime API及示例
			Java8新特性的功能已经更新了不少篇幅了,今天重点讲解时间日期库中DateTime相关处理.同样的,如果你现在依旧在项目中使用传统Date.Calendar和SimpleDateFormat等API ... 
- 包名targetPackage和目录名targetProject
			generatorConfig.xml中的 <javaModelGenerator targetPackage="edu.cn.pojo" targetProject=&qu ... 
- 从0开始学FreeRTOS-(创建任务)-2
			# 补充 开始今天的内容之前,先补充一下上篇文章[从单片机到操作系统-1](https://jiejietop.gitee.io/freertos-1/)的一点点遗漏的知识点. ```js BaseT ... 
- Java字段初始化规律
			首先先附上一段代码:public class InitializeBlockDemo { public static void main(String[] args) { InitializeBloc ... 
- HTML5存储--离线存储
			离线存储技术 HTML5提出了两大离线存储技术:localstorage与Application Cache,两者各有应用场景:传统还有离线存储技术为Cookie. 经过实践我们认为localstor ... 
- python编程基础之二十九
			栈和队列: 栈:先进后出,其他没多少特别之处了,一般可以用列表模拟栈,也可以用双端队列,封死一端. 队列:先进先出,也可以用列表模拟,但是一般用库函数,需要导collections 包:主要是为了解决 ... 
- golang初探与命令源码分析
			前段时间有群友在群里问一个go语言的问题: 就是有一个main.go的main函数里调用了另一个demo.go里的hello()函数.其中main.go和hello.go同属于main包.但是在mai ... 
