百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

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

yuyutoo 2024-12-22 21:45 5 浏览 0 评论

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


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


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


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


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



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


三、switch为什么不支持long?


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


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


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


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



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


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


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



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


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

往期精彩:

java中if与switch的那些事

String为什么不可变

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

ThreadLocal优化方案

作者介绍:

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

相关推荐

微软Win10/Win11版Copilot上线:支持OpenAI o3推理模型

IT之家4月3日消息,科技媒体WindowsLatest昨日(4月2日)发布博文,报道称Windows10、Windows11新版Copilot应用已摘掉Beta帽...

WinForm 双屏幕应用开发:原理、实现与优化

在当今的软件开发领域,多屏幕显示技术的应用越来越广泛。对于WinForm应用程序来说,能够支持双屏幕显示不仅可以提升用户体验,还能满足一些特定场景下的业务需求,比如在演示、监控或者多任务处理等场景...

推荐一个使用 C# 开发的 Windows10 磁贴美化小工具

...

OpenJDK 8 安装(openjdk 8 windows)

通常OpenJDK8和11都能互相编译和通用。我们建议使用11,但是如果你使用JDK8的话也是没有问题的。建议配置使用OpenJDK,不建议使用OracleJDK,主要是因为版...

基于 Linux 快速部署 OpenConnect VPN 服务(ocserv 实战指南)

一、前言在如今远程办公和内网穿透需求日益增长的背景下,搭建一套安全、稳定、高效的VPN系统显得尤为重要。OpenConnectServer(ocserv)是一个开源、高性能的VPN服务端软件...

巧妙设置让Edge浏览器更好用(edge怎么设置好用)

虽然现在新版本的Edge浏览器已经推出,但是毕竟还处于测试的状态中。而Win10系统里面自带的老版Edge浏览器,却越来越不被人重视。其实我们只需要根据实际情况对老版本的Edge浏览器进行一些简单的设...

WPF做一个漂亮的登录界面(wpf页面设计)

...

微软开源博客工具Open Live Writer更新:多项Bug修复

OpenLiveWriter前身是WindowsLiveWriter,是微软WindowsLive系列软件之一,曾经是博主们非常喜爱的一款所见即所得博文编辑工具,支持离线保存,还支持图像编辑...

基于OpenVINO的在线设计和虚拟试穿 | OPENAIGC大赛企业组优秀作品

在第二届拯救者杯OPENAIGC开发者大赛中,涌现出一批技术突出、创意卓越的作品。为了让这些优秀项目被更多人看到,我们特意开设了优秀作品报道专栏,旨在展示其独特之处和开发者的精彩故事。...

C#开源免费的Windows右键菜单管理工具

...

Windows10或11中隐藏的功能,用它再也不用担心电脑中病毒!

...

Python open函数详解(python open函数源码)

演示环境,操作系统:Win1021H2(64bit);Python解释器:3.8.10。open是Python的一个内置函数,一般用于本地文件的读写操作。用法如下。my_file=open(fi...

Windows 11 安装 Docker Desktop(Windows 11 安装助手 Windows 易升 关系)

...

Windows 11 新版发布:屏幕亮度自适应控制,小组件界面重新设计!

...

世界上最好用的Linux发行版之一,OpenSUSE安装及简单体验

背景之前无意在论坛里看到openSUSE的Linux发行版,被称为世界上最好用的Linux发行版之一(阔怕),一直想体验一下,于是这期做一个安装和简单体验教程吧。...

取消回复欢迎 发表评论: