史上将switch原理讲得最透彻的文章

大家好,我是贠学文,点击右上方“关注”,每天为您分享java程序员需要掌握的知识点干货。


凌晨四点的北京

上一期说了一下java判断语句中if和switch在使用上的区别,以及个人的使用习惯,今天来说一下他们在底层的实现原理。当然了,if的实现原理非常简单,就是顺序查找,没啥可说的,但是switch的原理,还是值得说一下的。


一、switch支持的类型


1.byte,short,char,int四种基本类型
2.byte,short,char,int四种基本类型对应包装类
3.String类型
4.enum类型


其实从严格意义上来讲,switch的底层,只支持int一种类型,但是其他类型可以通过各种方式转换为int类型,每种类型的转换方式如下:


1.byte,short,char三种基本类型可以隐式地自动转换为int类型


2.byte,short,char,int四种基本类型对于的包装类,实际上是做了自动拆箱,先转换成各自对应的基本类型后,在隐式的转换为int类型


3.String类型,取的是String对象的hashCode值,hashCode就是int类型


4.enum类型,enum类型实际上就是一个数组,取得是数组的下标。


但是看到这里大家会不会有一个疑问,那就是每种整数类型的都支持了,为什么没有支持long类型呢?这个问题我们后面会解答。


二、switch的实现原理


我们看下图1所示的代码以及图2对应的字节码:


图1


图2

我们在图1的代码中,case的分支条件有从11到20,这10个分支条件,那图2字节码中我标红的部分,是一个tableswitch指令,我们可以把这个指令的内容理解成一个数组,数组中的每个元素,冒号前面的,是记录的我们case分支条件的值,即11到20,此时我们记录start=11,end=20,而冒号后面的,即定位到这个分支条件后,要跳转到的执行代码的行数。如果你想查找某个值key,它会首先看你这个值是否在start和end的范围内,如果在,则直接用key-start,计算出数组的下标,找到数组中的元素,如果不在,则直接执行default部分,这种的查找方式,时间复杂度为O(1),效率非常高。


但是这是有人可能会问了,你图一的代码中,case分支的条件的值都是连续的,那如果不是连续的呢?是不是就不能用这种算法了。我们可以看下图3的代码:


图3

我们删掉了几个分支条件,让其不是连续的,然后我们在看图4的字节码:


图4

发现其实它会自动的把缺少的分支条件,自动的补齐,使其成为连续的,此时这种算法还是生效的。


但是我们图3的代码,虽然它的分支条件不连续,但是每个分支条件的值还都比较集中,这样它自动补齐的时候,需要补齐的数据也非常少,但是如果分支的条件不集中呢?这时如果再自动补齐,就需要补齐大量的数据,严重的浪费空间,所以这时候,这种算法就不合适了,我们可以看下图五的代码以及图六对应得字节码:


图5


图6

图5代码中,case分支条件非常不集中,所以我们在看图6的字节码中,这时就不在使用tableswitch指令了,而是使用了lookupswitch指令,这个指令了内容中,没有像tableswitch指令一样实现自动补齐,所以就不能根据数组下标去查找了,这时采用的二分查找的方式。


三、switch为什么不支持long?


1.上面我们在讲到switch原理的时候,提到了两个指令,一个tableswitch,一个lookupswitch,这两个指令中,支持的最大的范围就是int,所以无法支持long。


2.int的范围已经足够大了,已经到了20多个亿了,我们在日常的代码编写中,很少会有对这么大的数据做switch的,我觉得java的设计者,也是考虑到这一点,觉得没有必要支持long类型。


四、switch方式如何支持String类型


我们可以看下图7所示的代码和图8对于的字节码:


图7


图8

我们发现其实他是在底层调用了String的hasecode方法,然后把返回值作为case的分支条件,从而支持String类型。


五、switch方式如何支持enum类型


我们可以看下图九所示的代码和图十对于的字节码:


图9


图10

我们发现其实他是在底层调用了enum的ordinal方法,然后把返回值作为case的分支条件,从而支持enum类型。


到这里呢,switch的原理就说完了,但是还是像昨天说的一样,我在日常的编码中,几乎从来不用switch,虽然说它的效率要比if高,但是这种效率的差异,只有在分支条件特别多的时候才能体现出来。但是如果分支条件特别多了,不管用if还是switch,对后期的维护都是一个灾难。所以我在分支条件少的时候,会选择用if,当分支条件多的时候,我会用合适的设计模式来处理。

往期精彩:

java中if与switch的那些事

String为什么不可变

史上将String常量池讲得最透彻的文章

ThreadLocal优化方案

作者介绍:

贠学文,具有多有经验的java开发工程师,业余时间利用头条分享技术知识点与自己对技术的感悟,帮助对自己未来感到迷茫的程序员,在技术上得到提升。结识一些志同道合的朋友,相互促进,共同进步。

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章