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

说一说switch关键字的奥秘的更多相关文章
- 说说Java中你不知道switch关键字
Switch语法 switch作为Java内置关键字,却在项目中真正使用的比较少.关于switch,还是有那么一些奥秘的. 要什么switch,我有if-else 确实,项目中使用switch比较少的 ...
- 说说switch关键字
Switch语法 switch作为Java内置关键字,却在项目中真正使用的比较少.关于switch,还是有那么一些奥秘的. 要什么switch,我有if-else 确实,项目中使用switch比较少的 ...
- c#关键字详解
c#关键字 关键字是对编译器有特殊意义的预定义的保留标识符.它们不能在程序中用作普通标识符,除非在它们前面加上@前缀. 第一部分 一.访问关键字:base,this base:访问基类的成员. 用 ...
- 你好,C++(20).4.2.2 表达并列条件选择的switch语句:如果……如果……如果……
4.2.2 表达并列条件选择的switch语句:如果……如果……如果…… 在现实世界中,还有这样一类特殊的条件选择: 如果明天是晴天,我就穿T恤: 如果明天是阴天,我就穿衬衣: 如果明天是雨天,我就 ...
- Powershell Switch 条件
Powershell Switch 条件 6 21 1月, 2012 在 Powershell tagged Powershell教程/ 分支/ 字符串/ 数字/ 条件by Mooser Lee 本 ...
- 选择结构switch
1.选择结构switch switch 条件语句也是一种很常用的选择语句,它和if条件语句不同,它只能针对某个表达式的值作出判断,从而决定程序执行哪一段代码.例如,在程序中使用数字1~7来表示星期一到 ...
- Switch语句的参数是什么类型的?
在Java5以前,switch(expr)中,exper只能是byte,short,char,int类型. 从Java5开始,java中引入了枚举类型,即enum类型. 从Java7开始,exper还 ...
- 带标签的循环语句、switch
今天继续更新,控制流程的剩余部分内容,带标签的循环语句中的continue/break 的使用方法,以及switch关键字的使用方法.例1:带标签的continue/break.package com ...
- GoLang学习控制语句之switch
基本结构 相比较 C 和 Java 等其它语言而言,Go 语言中的 switch 结构使用上更加灵活.它接受任意形式的表达式,例如: switch var1 { case val1: ... case ...
随机推荐
- python 父类方法中使用不同的子类中的不同类对象
# coding:utf-8 class Animal(object): def __init__(self): self._name = None self._f = None def eat(se ...
- Java自学-集合框架 ArrayList常用方法
ArrayList常用方法 步骤 1 : 增加 add 有两种用法: 第一种是直接add对象,把对象加在最后面 heros.add(new Hero("hero " + i)); ...
- 钉钉企业内部H5微应用开发
企业内部H5微应用开发 分为 服务端API和前端API的开发,主要涉及到进入应用免登流程和JSAPI鉴权. JSAPI鉴权开发步骤: 1.创建H5微应用 登入钉钉开放平台(https://open-d ...
- JavaScript RegExp(正则表达式) 对象
正则表达式是描述字符模式的对象.正则表达式用于在文本上执行模式匹配和“搜索和替换”功能. var patt = /JC2182/i 示例说明: /JC2182/i - 是一个正则表达式. JC2182 ...
- windows7系统 执行应用程序报 Error accessing specified device (Error: 2)
--------------------------- ---------------------------Error accessing specified device (Error: 2) - ...
- BeautyWe.js 一套专注于微信小程序的开发范式
摘要: 小程序框架... 作者:JerryC 原文:BeautyWe.js 一套专注于微信小程序的开发范式 Fundebug经授权转载,版权归原作者所有. 官网:beautywejs.com Repo ...
- 201871010128-杨丽霞《面向对象程序设计(java)》第十五周学习总结
201871010128-杨丽霞<面向对象程序设计(java)>第十五周学习总结 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ ...
- SHELL脚本--变量
环境变量 环境变量就是运行在"环境"上下文的,在这个上下文都可以引用.例如,常见的cd.ls等命令严格来说应该使用绝对路径如/bin/ls来执行,由于/bin目录加入到了PATH环 ...
- Access-Control-Allow-Origin 响应一个携带身份信息(Credential)的HTTP请求时,必需指定具体的域,不能用通配符
https://www.cnblogs.com/raind/p/10771778.html Access-Control-Allow-Origin.HTTP响应头,指定服务器端允许进行跨域资源访问的来 ...
- POJ3630-Phone List-(字典树)
一直没有学字典树,听起来很唬人,闲来无事找一道入门题做做. 字典树:又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以 ...