Java中switch支持String是通过编译期预计算hashCode生成跳转表、运行期用equals校验实现的;因long无法无歧义映射为int,故不支持。

它既保持了 switch 的高效性,又保证了语义正确性。下面分三部分讲清楚核心实现逻辑:
编译期:把每个 case 字符串转成 hashCode() 值
当你写:
switch (str) {
case "apple": ... break;
case "banana": ... break;
}
编译器会预先计算 "apple".hashCode() 和 "banana".hashCode(),生成一个整数跳转表(tableswitch 或 lookupswitch)。这样运行时就能用 int 做快速分支定位,避免逐个字符串比对。
- 所有 case 字符串必须是编译期常量(字面量或 static final String)
- 如果两个字符串 hashCode 碰撞(比如 "Aa" 和 "BB"),编译器仍会为它们生成不同分支入口
运行期:用 equals() 做最终确认
跳转到候选分支后,JVM 并不直接执行代码,而是插入一条 if (str.equals("apple")) 判断。
- 这是为了兜底处理哈希冲突——即使 hashCode 相同,内容不同也不能匹配
- 所以 switch 对 String 的语义等价于:先查哈希表找可能分支,再用 equals() 精确验证
- 这也解释了为什么传入 null 会抛 NullPointerException:str.hashCode() 或 str.equals(...) 都会在 null 上失败
为什么 long 不行,String 却可以?
关键不在“是不是引用类型”,而在于是否能安全映射为 int:
- long 范围远超 int(−2⁶³ ~ 2⁶³−1 vs −2³¹ ~ 2³¹−1),截断高位会导致歧义,JVM 明确禁止
- String 的 hashCode() 方法稳定返回 int,且所有 case 字面量的哈希值可在编译期固化进 class 文件,配合运行时 equals() 校验,既高效又可靠
- 枚举、byte/short/char/int 同理——都可无歧义映射为唯一 int 值


















