关键词:
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进阶的文章,感谢关注
「译」foreach循环中你不知道的3件事(代码片段)
前言本文925字,阅读大约需要7分钟。总括:forEach循环中你不知道的3件事。原文地址:3thingsyoudidn’tknowabouttheforEachloopinJS公众号:「前端进阶学习」,回复「666」,获取一揽子前端技术书籍自弃者扶不起,自强者击不倒。正文你... 查看详情
js中你不知道的一些概念知识(代码片段)
DOM元素e的e.getAttribute(propName)和e.propName有什么区别和联系e.getAttribute(),是标准DOM操作文档元素属性的方法,具有通用性可在任意文档上使用,返回元素在源文件中设置的属性e.propName通常是在HTML文档中访问特定元素的... 查看详情
你不知道的javascript(上卷)小结
...的小缺点,一是,有些东西已经和实际不一样了,比如说关键字module,现在已经和import合并了,之类的,这个跟内容质量关系不大,主要是技术发展总会有变更;二是,有些行文内容,比如列出1、2点之类的,感觉彼此之间 查看详情
php代码审计中你不知道的牛叉技术点
一、前言php代码审计如字面意思,对php源代码进行审查,理解代码的逻辑,发现其中的安全漏洞。如审计代码中是否存在sql注入,则检查代码中sql语句到数据库的传输和调用过程。入门php代码审计实际并无什么门槛要求,只需要... 查看详情
java中你所不知道的cas操作
...并重试。2.CAS操作和synchronized有什么区别呢 synchronized关键字采用悲观锁技术,线程独享锁,其他线程 查看详情
asp.netcore中间件应用实践中你不知道的那些事(代码片段)
一、概述这篇文章主要分享Endpoint终结点路由的中间件的应用场景及实践案例,不讲述其工作原理,如果需要了解工作原理的同学,可以点击查看以下两篇解读文章:Asp.NetCoreEndPoint终结点路由工作原理解读ASP.NETCORE管道模型及中... 查看详情
javascript中你不知道的5个json-使用技巧(代码片段)
开发中,经常使用 JSON.stringify(object) 来序列化对象,但除了第一个参数外,还有其它参数可用...格式化//默认的JSON.stringify(object)出来数据是一行字符串constuser=name:'JackieDYH',age:30,isAdmin:true,friends:['小可爱... 查看详情
说说关于servlet你不知道的知识(代码片段)
什么是Servlet? JavaWeb技术是当今主流的互联网Web应用技术之一,而Servlet是JavaWeb技术的核心基础。那么什么是Servlet,什么是Servlet容器呢? 最简单的介绍,Servlet是Sun公司提供的一门用于开发动... 查看详情
你不知道的javascript笔记
this和对象原型this是一个很特别的关键字,被自动定义在所有函数的作用域中//foo.count是0,字面理解是错误的 functionfoo(num){ console.log("foo:"+num); &n 查看详情
你不知道的javascript笔记
... 区分函数声明和函数表达式最简单的方法是看function关键字出现的位置,如果function是声明中的第一个词,那么是函数声明,否则是函数表达式。(functionfoo(){} 查看详情
云栖大会中你不可以错过的技术盛宴!
2017阿里云杭州云栖大会ClouderLab探秘带上电脑去云栖,与专家面对面顺便拿认证!报名9月30日截止! 杭州云栖大会推出的4场ClouderLab开放实验室,为企业级技术人员提供了一个动手实操的实验平台,帮助他们清晰理解云计算... 查看详情
java——final关键字
前言Java中的关键字final的含义通常为“这是无法改变的”。下面将介绍final用于修饰数据、方法和类的这三种情况。final数据许多编程语言都有某种方法,来向告诉编译器这一块数据是不变的。有时候数据的恒定不变会很有用,... 查看详情
java——switch选择结构
...块的表示。switch语法格式: switch选择结构用到了四个关键字 :》switch:表示“开关”这个开关就是switch关键字后面小括号里的表达式的值,jdk1.7后, 查看详情
《你不知道的js(中卷①)》语法(代码片段)
...grammar)与词法(syntax)不同。后者强调语言的运算符、关键字等。而语法定义了此法规则是如何构成可运行的程序代码的。一)、语句和表达式:语句(statement)与表达式(expression),举例说明:vara=3*6;a=3*6是一个赋值表达式... 查看详情
你不知道的javascript事件(代码片段)
...提出了完全相反的的概念:事件冒泡和事件捕获。下面就说说这两种事件流:事件冒泡事件冒泡,就是说时间开始时由具体的元素接受,然后逐级向上传播到较为不具体的节点。看看下面的图就比较清楚了:比如说在图中的<di... 查看详情
java8中你可能不知道的一些地方之stream实战(代码片段)
Optional<T>类(java.util.Optional)是一个容器类,代表一个值存在或不存在,原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。Optional对象构建&值获取方法实例代码如下Optional<Str... 查看详情
java8中你可能不知道的一些地方之optional实战(代码片段)
Optional<T>类(java.util.Optional)是一个容器类,代表一个值存在或不存在,原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。Optional对象构建&值获取方法实例代码如下Optional<Str... 查看详情
java8中你可能不知道的一些地方之lambda(代码片段)
Lambda表达式(也称为闭包),它允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理。很多语言(Groovy、Scala等)从设计之初就支持Lambda表达式。但是java中使用的是匿名内部类代替。最后借助强大的社区力量... 查看详情