switch 是如何匹配枚举和字符串的?

本文比较了Java中if和switch语句的执行效率,指出switch由于底层使用tableswitch和lookupswitch结构,当值在预设范围内时,执行速度更快。特别讨论了switch对不同数据类型(包括枚举和字符串)的匹配机制。
摘要由CSDN通过智能技术生成

1、在 Java 中,if 和 switch 哪一个执行效率更高?

结论:switch 平均更快

public class Animal {
​
​
​
}
​
​
class Dog extends Animal{
​
}
class Cat extends Animal{
​
}
​
class Pig extends Animal{
​
}
​
​
​
    public static Animal test1(int n) {
        if (n == 1) {
            return new Dog();
        } else if (n == 2) {
            return new Cat();
        } else if (n == 3) {
            return new Pig();
        } else {
            return null;
        }
    }
​
​
    public static Animal test2(int n) {
        return switch (n) {
            case 1 -> new Dog();
            case 2 -> new Cat();
            case 3 -> new Pig();
            default -> null;
        };
    }
​

说明:

1、对于 if:在 Java 的字节码层面,if 条件语句和我们编写的代码是类似的,也是按照 if(?),if(?) 的方式进行判断的,

若最后一个 if 条件才满足就会判断所有的 if 条件判断语句,依次向下执行。

2、对于 switch:在 Java 底层,对于 switch 语句会维护一个类似 HashMap 的数据结构名字叫做 tableswitch ;首先会有上界(high)和下界(low)。

例如上面的代码中 (high,low) 就是 (3,1) 。HashMap 中 (key,value) 存储的数据是 (n的值,指向执行的代码) 。

所以可以知道,对于 switch 语句,当给定的值不在上界和下界的区间时就会直接返回,当在区间类,也可以根据 HashMap 数据结构马上找到需要执行的代码。这样就比 if 语句快很多了。(其中28,36,44表示字节码对应的行号)

2、 底层 switch 使用了几种表结构?

在使用 switch 事,底层有 tableswitch 和 lookupswitch 两种表结构。

两种表结构大致是相同的,当 switch 语句中 case 中的值相对集中时就会采用 tableswitch 结构。如下,tableswitch表格大小情况:

case值连续

当 case 的值为 1,2,3 是会将 索引为 0,1,2 的 value 指向执行代码,也会将其指向 null。 

 case值不连续

当 case 的值为 1,2,5 是会将 索引为 0,1,4 的 value 指向执行代码,当 n 的值为 3,4 时,对应的索引就是 2,3 。也会将其指向 null。

当 case 中的数据不集中时,例如下代码:case 中的数据间隙很大。就会使用 lookupswitch 结构

    public static Animal test3(int n) {
        return switch (n) {
            case 100 -> new Dog();
            case 300 -> new Pig();
            case 200 -> new Cat();
            default -> null;
        };
    }

对应的 lookupswitch 表结构如下:会根据 case 中的数据进行排序,然后然后为每一个数据指定一个从 0 到 n 的索引,相应的索引对应指定的具体数据,进一步指向相关的执行代码。

当执行代码时,当接收到数据 n 时,会将其转化根据当前的相关规则生成指定的索引。进一步找到真实需要执行的代码【这部分和 tableswitch 类似】。

3、switch 可以匹配的数据类型?

从 JDK1.0 开始 switch 就可以匹配 int 、byte、short 和 char 四种数据类型。

从 JDK1.5 开始,引入了相关的包装类 Integer、Byte、Short 和 Character 四种。

从 JDK 1.7 开始,引入了 String 和 Enum 类型。

目前 JDK 中的 switch 一种支持这 10 中数据类型。

int 、byte、short 和 char;Integer、Byte、Short 和 Character 这 8 中就是通过tableswitch 和 lookupswitch 进行匹配的,那么 String 和 枚举是如何进行匹配的呢?

4、switch 是如何匹配枚举类型的?

定义一个枚举:

public enum Day {
    MON, TUE, WED, THU, FIR, SAT, SUN;
}
​

例如下列代码

    public static String test4(Day day) {
        return switch (day) {
            case MON, TUE, WED, THU, FIR -> "工作日";
            case SAT, SUN -> "休息日";
            default -> "";
        };
    }

如下图所示,在匹配枚举类型时,底层维护了两个表格。对于枚举类型,每一个枚举变量都有一个相应的序号,从 0 开始。使用 ordinal() 方法就可以获取相关的序号。

第一张表格就是 Java 维护的数组,索引部分就是枚举的序号,值的部分就是连续的整数。

第二张表就是一张 tableswitch,它会根据第一张表格的值生成一个下界。tableswitch 表格里面的值就对应相应的代码行。

执行流程是:传递一个枚举对象,获取相关的序号,根据序号找到值,根据值减去下界就是tableswitch 表格中的索引,然后再根据索引执行相关的代码。

5、switch 在底层是如何匹配字符串类型的?

如下代码

    public static String test5(String s) {
        return switch (s) {
            case "1", "2", "3", "4", "5" -> "工作日";
            case "6", "7" -> "休息日";
            default -> "不合法";
        };
    }

switch 匹配 String 的执行流程

  1. 计算所有 case 里面的字符串的 hashCode,获取下界。
  2. 建立一个 tableswitch 表格,索引部分就是每一个 hashCode - 下界,值的部分指向了一个 if 条件判断语句。在 if 条件判断部分有一个变量 t ,初始值为 -1,后面会根据这个 t 的值去第二个 tableswitch 表格中进一步查找。
  3. 在比较第一个表格时,当得出的索引为 3 时,会进一步 if 判断当前的 s 的值是不是 "4",匹配成功地情况下才会将变量 t 进行赋值,进一步去第二个 tableswitch 中查询。

思考:

每一个字符串都有一个唯一的 hashCode,没什么要通过 if 维护两个 tableswitch 表格呢?

解答:因为不同的字符串的 hashCode 值可能会相同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值