You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 11 String类hashCode方法为何使用局部变量h?

Java 11 String.hashCode里局部变量h的作用

先看Java 11中String.hashCode()的核心代码:

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        hash = h = isLatin1() ? StringLatin1.hashCode(value)
                              : StringUTF16.hashCode(value);
    }
    return h;
}

核心是性能优化,同时兼顾并发场景的合理性

1. 性能:减少堆内存访问开销

实例变量hash存在堆上的String对象里,而局部变量h存在栈帧的局部变量表中,栈内存的访问速度比堆内存快得多。先把hash的值读到h里,后续的判断、赋值和返回都直接操作栈上的h,避免了多次访问堆上的hash字段,能明显提升方法执行效率。

2. 并发场景:避免重复计算

虽然String是不可变对象,但hash字段是延迟初始化的——只有第一次调用hashCode()时才会计算赋值。如果多个线程同时首次调用同一个String实例的hashCode(),可能因为JVM内存可见性的问题,每个线程都看到hash是0,进而重复计算哈希值。

用了局部变量h之后,每个线程会先把当前hash的值读到自己栈帧的h中:

  • 如果当前线程判断h为0,就计算哈希值,同时赋值给堆上的hash和栈上的h,最后返回h;
  • 就算其他线程同时修改了堆上的hash,当前线程还是用自己栈里的h完成计算和返回,不会重复计算,节省了不必要的资源消耗。而且因为String不可变,value数组不会变,所有线程计算出的哈希结果肯定是一样的,最终hash字段的值也会是正确的。

关于“线程安全”说法的澄清

之前有回答说这是为了线程安全,其实更准确的是避免并发场景下的重复计算浪费,而非保证线程安全——毕竟String的不可变性已经确保了value数组不会被修改,哈希计算结果是确定的。就算多个线程重复计算,最终hash的值也会是同一个正确结果,只是白耗算力,而h的引入刚好避免了这点。

不是单纯的风格选择

这绝对不是代码风格的偏好,是JDK开发团队经过性能测试和并发场景考量后的优化手段,在多个JDK版本的String实现里都能看到类似的局部变量用法。

内容的提问来源于stack exchange,提问作者Massimiliano Micol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 23:02:48