switch 底层执行原理
switch 语句根据一个整数索引值进行多重分支, 底层采用跳转表这种数据结构跳转表是一个数组, 表项 i 对应代码段的地址, 当 switch 索引值等于表项 i 时采取对应的程序操作
简单可理解为: 执行 switch 时生成一个长度为最大 case 常量+1 的数组, 程序首先判断 switch 变量是否大于最大 case 常量, 若大于, 则跳到 default 分支处理; 否则取得数组索引号为 switch 变量值大小, 取得数组对应值即为相应 case 代码块地址, 程序接着跳到此地址执行, 完成分支的跳转
但实际计算机底层实现这一操作会更加复杂一点, 以下参考深入理解操作机系统
图 a 是一个简单的 switch 例子, 对于 case 值有 100102~104106;case 值 102 与 104 是没有 break 语句结尾
图 b 是使用 C 语言的扩展形式来描述的, 每个表项都是一个代码块的地址 (指针), 这里的 && 指的就是 &
执行 switch 时, 会生成一张跳转表, 表项数为 (最大 case 值 - 最小 case 值+1), 跳转表是一个数组, 数组是一段连续的内存, jt 数组中包含了 7 个表项 (数组索引对应值), 每个都是指向对应代码块的指针
编译器将 switch 值 n - 最小 case 值 (100), 把取值范围移动到 0 至 6 之间, 创建出一个新的程序变量 index 首先判断 index 是否大于 6, 来判断是否在范围之外, 如果超出直接执行 default, 即 log_def 指针对应代码块
否则, 根据索引的值直接跳转不同位置
执行 if-else 是逐个条件进行判断, 直到命中; 与 if-else 语句相比, 使用跳转表的优点是执行 switch 语句的时间与数量无关, 且读取 switch 参数时只读取一次, 就可跳到对应分支; 缺点是维系了一个连续的数组, 实际时使用空间换时间
补充: 正因为要将 case 值转换为表项 i, 以及 switch 值要根据 case 值转换为对应数组索引, 所以 switch 入参时是不支持 bytefloatdouble 型, 以及对应 case 分支也是不支持 bytefloatdouble 型的
关于 switch 与 if-else 的简单优化
暂且不说 if-else 与 switch 相比哪一个的执行效率高, 先就知道原理后, 我们应如何去优化
if-else
对于 if-else, 在系统是自上而下逐个条件去判断, 直到命中; 所以应将机率大的条件置于最前面以下给出一个简单例子
- double random = Math.random() * 100; // 生成 0-100 的随机数
- if (random > 10) { //90%
- } else if (random > 5) { //5%
- } else { // 剩下的 5%
- }
对于条件机率相等或是条件个数非常多的情况, 因为 switch 的执行时间与条件数量无关, 他是根据 switch 值直接跳转到对应分支, 所以可以选择 switch 代替 if-else
switch
对于 switch, 实际上是根据 case 最小值与最大值, 维系了一段连续的内存空间, 以空间换取时间以下给出一个简单的反例, 最大值与最小值跨度较大, 且之间没有更多的条件情况, 那个无疑实际申请的很多空间是没用的, 所以就应考虑使用 if-else 在代替
- int random = (int) Math.random() * 100; // 生成 0-100 的随机数
- switch (random) {
- case 0:
- break;
- case 100:
- break;
- }
深入操作机系统下载链接: http://download.csdn.net/download/abrazen_zz/9706844
来源: http://blog.csdn.net/abrazen_zz/article/details/79250450