java底层,为什么switch的效率比iflelse高

学习Java的人都知道这样的现象,能够使用switch的地方,就一定可以使用if/else,if/else,…来代替。比如下面switch代码

int a = 10;
switch(a){
    case 5:
        System.out.println("5");
        break;
    case 3:
        System.out.println("3");
        break;
    case 1:
        System.out.println("1");
        break;
    default:
        System.out.println("default");
        break;
}

我们可以使用if/else,if/else,…替换为下面代码:

int a = 10;
if(a == 5){
    System.out.println("5");
}else if( a= =3 ){
    System.out.println("3");
}else if( a= =1 ){
    System.out.println("1");
}else{
    System.out.println("default");
}

从逻辑上讲,if/else, if/else if/else,三元运算符,switch都可以只用if代替,但使用不同的语法表达更简洁,在条件比较多的时候,switch从性能上也更高。但是为什么switch的性能会更高呢?这就涉及到条件判断的最底层了。
程序的执行最终是会翻译成一条条指令去执行,CPU有一个指令指示器,指示器指向要执行的指令,CPU根据指示器的指示去执行对应的指令。执行一个指令后,指令指示器会自动指向挨着的下一个指令。但有一些特殊的指令,称为跳转指令,这些指令会修改指令指示器的下一个指向,让CPU跳到一个指定的地方执行。跳转指令有两种,一种是条件跳转,另一种是无条件跳转。条件跳转是指检查某个条件,满足则跳转到指定位置执行,不满足则继续向下执行,无条件跳转则是直接进行跳转,跳转到指定的位置执行。而if else 在底层实际上是转换成这些跳转指令执行的。举个例子:

int x=10;[/align]if(x= =10)
{
    System.out.println("程序员");
}
System.out.println("播客");

底层翻译为跳转指令如下:

1:int x=10;
2:条件跳转:如果x= =10,跳转到第4行;
3:无条件跳转:跳转到第7行;
4:{
5:    System.out.println("程序员");
6:}
7:System.out.println("播客");

看到这儿你肯定会有一个疑问,为什么这儿还要有一个无条件跳转呢。没有这个无条件跳转可以吗?答案是不可以,如果没有这个无条件跳转,不管条件跳转里面的条件满不满足,大括号里面的“黑马程序员”都会执行的。我们来分析一下假如没有无条件跳转:如果x= =10则跳转到大括号执行。如果x!=10呢,cpu继续执行下一条指令,而下一条指令也就是大括号里面的内容。再来分析一下有无条件跳转的情况:如果x= =0则会把无条件跳转的这一行指令跳过,直接进入大括号执行。如果x!=10,则继续执行下一条指令,而下一条指令则是无条件跳转,则会跳转到第7行打印传智播客。也有的时候,编译器会翻译成下面的情况,

1:int x=10;
2:条件跳转:如果x!=10,跳转到第6行;
3:{
4:    System.out.println("程序员");
5:}
[align=left] 6:System.out.println("播客");

这样就不需要无条件跳转指令,具体怎么翻译和编译期的实现有关,在单一if的情况下可能不用无条件跳转指令,但稍微复杂一些的情况都需要,下面我把本文第一段提到的代码使用条件跳转指令翻译一下。

int a = 10;[/align]if(a = = 5){
    System.out.println("5");
}else if( a= =3 ){
    System.out.println("3");
}else if( a= =1 ){
    System.out.println("1");
}else{
    System.out.println("default");
}
System.out.println("播客");

翻译如下:

1:int a = 10;
2:条件跳转:如果a= =5,跳转到第4行;
3:无条件跳转:跳转到第7行;
4:{
5:    System.out.println("5");
6:}
7:条件跳转:如果a= =3,跳转到第9行;
8:无条件跳转:跳转到第12行;
9:{
10:    System.out.println("3");
11:}
12:条件跳转:如果x= =1,跳转到第14行;
13:无条件跳转:跳转到第17行;
14:{
15:    System.out.println("1");
16:}
17:条件跳转:如果x!=1&&x!=3&&x!=5,跳转到第19行;
18:无条件跳转:跳转到第22行;
19:{
20:    System.out.println("default");
21:}
22: //其他代码

if, if/else, if/else if/else, 三元运算符都会转换为条件跳转和无条件跳转。但switch不太一样。switch的编译是这样的,如果分支比较少,可能会翻译为跳转指令。但如果分支比较多,使用条件跳转就会进行很多次的比较运算,效率比较低,这时候编译器会使用一种更为高效的方式,叫跳转表。跳转表是一个映射表,存储了case的值以及要跳转到的地址,形如:
在这里插入图片描述

跳转表为什么会更为高效呢?因为,其中的值必须为整数,且按大小顺序排序。(switch值的类型可以是byte,short, int, char, 枚举和String。其中byte/short/int本来就是整数,char本质上也是整数,而枚举类型也有对应的整数,String用于switch时也会转换为整数)按大小排序的整数可以使用高效的二分查找。程序源代码中的case值排列不要求是排序的,编译器会自动排序。如果值是连续的,则跳转表还会进行特殊优化,优化为一个数组,连找都不用找了,值就是数组的下标索引,直接根据值就可以找到跳转的地址。即使值不是连续的,但数字比较密集,差的不多,编译器也可能会优化为一个数组型的跳转表,没有的值指向default分支。这个是可以利用反编译工具进行验证的,举例如下:
在这里插入图片描述

上面是我们编写的一个switch判断的源代码。我们编译后生成class文件,再利用反编译工具把class文件还原成源码。见下图:
在这里插入图片描述
这足以说明如果case的值是连续的,或者值不是连续的,但数字比较密集,差的不多,编译器也可能会优化为一个数组型的跳转表,没有的值指向default分支,而此时的跳转表数组是
在这里插入图片描述

总结:
一般能够用switch表示的逻辑结构,都可以使用ifelse进行表示。但是如果判断的条件分支比较多的时候,建议多使用switch,因为switch的执行效率高,这源于switch在被编译的时候,其跳转指令会被编译为一个数组,从而使用查表法 二分法查找等高效的方式进行指令的跳转。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 Java 中,switch 语句的底层实现是使用哈希表。在编译时,编译器会生成一个哈希表并将每个 case 的值映射到相应的代码偏移量。当执行 switch 语句时,程序会在哈希表中查找与表达式匹配的值,并跳转到相应的代码偏移量处执行。 这种实现方式的优势在于,可以在常数时间内完成查找,因此 switch 语句的性能很好。 请注意,switch 语句只能用于整数类型(byte、short、char、int)和枚举类型,不能用于浮点数类型或字符串类型。 ### 回答2: Java中的switch语句在底层实现上使用了一种叫作查表法的算法。这种算法通过查找固定的表格来决定跳转到哪个case分支。 在编译时,Java编译器会将switch语句中的case分支的值生成成一个固定的表格,表格中的每个条目包含了case分支的值和该分支对应的代码位置。当程序执行到switch语句时,会根据给定的表达式的值去查找表格,以确定应该跳转到哪个case分支执行相关代码。 查找表格的算法会根据给定的表达式的值进行比较操作,并依次比较表格中的每个条目的值,直到找到匹配的条目,然后跳转到该条目对应的代码位置执行相应的代码。如果没有匹配的条目,可能会跳转到一个默认的分支。 这种查表法的实现方式相较于使用多个嵌套的if-else语句来判断每个分支的值更效一些,因为它直接跳转到目标代码位置,而不需要进行逐个比较和判断。 需要注意的是,为了能够使用查表法,switch语句的表达式必须是一个可以用整型或字符类型表示的常量或者枚举类型,并且case分支的值也必须是常量或枚举类型的值。 总的来说,Java底层关于switch的case的具体算法是通过查表法来匹配给定表达式的值并跳转到对应的代码位置执行相关代码。 ### 回答3: Java中的switch语句是用于多分支选择的一种结构,它的底层实现涉及到与计算机硬件和编译器的配合。具体算法如下: 1. 首先,编译器会将switch语句的表达式的值与每个case语句的常量值进行比较。这个比较过程可以使用简单的数学运算来实现,例如比较大小或计算哈希值。 2. 当找到与表达式值匹配的case语句时,程序将执行匹配的case代码块。这个过程类似于一系列if-else语句,只是使用了更效的匹配和跳转机制。 3. 如果找不到与表达式值匹配的case语句,那么程序将执行default代码块(如果存在)。default相当于if-else结构中的else部分,用于处理一些默认情况。 4. 在执行case代码块之前,编译器会根据具体的条件和情况,可能会使用一些优化策略,例如使用查表法或计算跳转表,以提性能和效率。 总之,switch语句的具体算法是通过与表达式值的比较来选择执行的代码块,其中可能会使用一些优化策略以提效率。这些底层机制对于开发者来说是透明的,因为Java语言已经帮我们抽象出了更易于理解和使用的switch语句结构。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值