JVM字节码分析--switch语法糖

本文深入探讨了JVM中switch语句的底层实现,包括tableswitch和lookupswitch两种指令的使用。当case值紧凑时,tableswitch提供O(1)的查找效率;而对于值相差较大的case,lookupswitch采用O(logn)的二分查找策略。此外,自JDK7起,String类型的switch也进行了详细解释,涉及hashCode计算和后续的字符串匹配步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JVM字节码分析--switch语法糖

一、switch 底层实现

编译器使用 tableswitch 和 lookupswitch 两个指令来生成 switch 语句的编译代码:

int chooseNear(int i) {
    switch (i) {
        case 0: return 0;
        case 1: return 1;
        case 4: return 4;
        default: return -1;
    }
}

字节码如下:

0: iload_1
1: tableswitch   { // 100 to 104
         0: 36
         1: 38
         2: 42
         3: 42
         4: 40
     default: 42
}

可见在1到4之间字节码填充了虚假的 2、3 方便 tableswitch 通过计算偏移量即可一次找到对应的case 。比如case为1时,只需计算1 - 0 = 1即可得到偏移量为1,从 tableswitch 中取出下标为 1 的case 即可,此时算法复杂度为O(1)。

但 tableswitch 只适用于case值紧凑的情况,若case值相差太大,JVM 则自动使用 lookupswitch 指令生成编译代码:

int chooseFar(int i) {
    switch (i) {
        case 2: return 1;
        case 20: return 10;
        case 300: return 100;
        default: return -1;
    }
}

字节码如下:

0: iload_1
1: lookupswitch  { // 3
           2: 36
          20: 38
         300: 41
     default: 44
}

2、20、300相差较大,使用 lookupswitch 指令实际上通过二分查找的方式寻找对应的 case ,此时算法复杂度为 O(logn)

二、String的switch实现

String 的 switch 在 JDK7 中引入, 其实现流程分为以下几步:

  1. 计算字符串 hashCode
  2. 使用 lookupswitch 对整型 hashCode 进行分支
  3. 对相同 hashCode 值的字符串进行最后的字符串匹配
  4. 执行 case 块代码

例如下面的代码:

public int test(String name) {
    switch (name) {
        case "Java":
            return 100;
        case "Kotlin":
            return 200;
        default:
            return -1;
    }
}

字节码如下:
 0: aload_1
 1: astore_2
 2: iconst_m1
 3: istore_3
 
 4: aload_2
 5: invokevirtual #2                  // Method java/lang/String.hashCode:()I
 8: lookupswitch  { // 2
     -2041707231: 50 // 对应 "Kotlin".hashCode()
         2301506: 36 // 对应 "Java".hashCode()
         default: 61
    }
    
36: aload_2
37: ldc           #3                  // String Java
39: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
42: ifeq          61
45: iconst_0
46: istore_3
47: goto          61

50: aload_2
51: ldc           #5                  // String Kotlin
53: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
56: ifeq          61
59: iconst_1
60: istore_3

61: iload_3
62: lookupswitch  { // 2
               0: 88
               1: 91
         default: 95
    }
    
// 88 ~ 90
88: bipush        100
90: ireturn

91: sipush        200
94: ireturn

95: iconst_m1
96: ireturn

经过字节码翻译,实际上代码可翻译为:

public int test_translate(String name) {
	//对应0--3
    String tmpName = name;
    int matchIndex = -1;
    
    //对应4--60
    switch (tmpName.hashCode()) {
        case -2041707231:
            if (tmpName.equals("Kotlin")) {
                matchIndex = 1;
            }
            break;
        case 2301506:
            if (tmpName.equals("Java")) {
                matchIndex = 0;
            }
            break;
        default:
            break;
    }

	//对应61--96
    switch (matchIndex) {
        case 0:
            return 100;
        case 1:
            return 200;
        default:
            return -1;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值