为什么 switch 语句效率比 if-else 语句高
为什么 switch 语句效率比 if-else 语句高
Sunswitch
语句和 if-else
语句都是条件控制语句,为什么说 switch
语句效率比
if-else
语句高呢?
要回答这个问题,我们先要了解条件控制语句的底层原理是什么。
在计算机底层程序最终都会转换成一条条的指令,CPU 有一个程序计数器(PC),指向下一条要执行的指令,CPU 根据程序计数器的指示加载指令并且执行。
指令大部分是具体的操作和运算,执行完一条指令后,程序计数器会自动指向挨着的下一条指令。
但有一些特殊的指令,称为跳转指令,if-else
语句实际上就会转换为这些跳转指令。
跳转指令会修改程序计数器的值,让 CPU 跳到一个指定的地方执行。
跳转指令有两种:
- 条件跳转:检查某个条件,满足则进行跳转;
- 无条件跳转:直接进行跳转。
下面一个简单的if语句:
1 | if (a > b) { |
可能被编译为类似这样的汇编代码:
1 | ; 假设a在eax,b在ebx,c在ecx |
这里:
JLE
(Jump if Less or Equal)是条件跳转指令,根据标志位决定是否跳转JMP
是无条件跳转指令
if
、if/else
、if/else if/else
、三元运算符
都会转换为条件跳转和无条件跳转,但 switch
语句不太一样。
switch
的转换和具体系统实现有关:
- 如果分支比较少,可能会转换为跳转指令;
- 如果分支比较多,使用条件跳转会进行很多次的比较运算,效率比较低,可能会使用一种更为高效的方式,叫跳转表。
跳转表是一个映射表,存储了可能的值以及要跳转到的地址,如下表所示:
条件值 | 跳转地址 |
---|---|
值 1 | 指令 1 的地址 |
值 2 | 指令 2 的地址 |
… | … |
值 n | 指令 n 的地址 |
跳转表中的值必须为整数,且按大小顺序排序,这样就可以使用高效的二分查找。
如果值是连续的,则跳转表还会进行特殊优化,优化为一个数组,值就是数组的下标索引。即使值不是连续的,但数字比较密集,编译器也可能会优化为一个数组型的跳转表,没有的值指向
default
分支。
switch
值的类型可以是
byte
、short
、int
、char
、enum
和 String
,其中 byte/short/int
本来就是整数,char
本质上也是整数,而 enum
类型也有对应的整数。
String
用于 switch
时会通过
hashCode()
方法转换为整数,但不同 String
的
hashCode
可能相同,跳转后会再次根据 String
的内容进行比较判断。
但是 switch
不可以使用
long
,因为跳转表值的存储空间一般为 32 位,容纳不下
long
。