string的hashcode()采用缓存机制,首次计算后存入私有字段hash,后续直接返回;其哈希值按多项式公式s[0]×31^(n−1)+…+s[n−1]迭代计算,即h=31*h+val[i],选用质数31以降低冲突并支持jvm位运算优化。

String 的 hashCode() 方法采用“首次计算、后续复用”的缓存策略,核心依赖字符串的不可变性来保证缓存安全。它不是每次调用都重新算,而是用一个私有字段 hash 记住结果,下次直接返回。
哈希值怎么算出来的
计算使用标准多项式公式,基于字符的 Unicode 值(UTF-16 代码单元):
- 公式是:
h = s[0] × 31^(n−1) + s[1] × 31^(n−2) + … + s[n−1] - 实际代码中通过迭代实现:
h = 31 * h + val[i],从左到右逐个字符累加 - 乘数选 31 是因为它是质数,能减少哈希冲突,且 JVM 可优化为位移加减(
31 * i == (i ) - 空字符串
""的哈希值就是 0,所以不能单靠hash == 0判断是否已计算
缓存机制怎么工作的
缓存靠一个普通 int hash 字段(非 volatile,也非 final),默认初始值为 0:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 首次调用时,若
hash == 0且字符串长度大于 0,才执行计算,并把结果写入hash - 之后所有调用都跳过计算,直接返回
hash的当前值 - 设计上接受多线程下极小概率的重复计算(比如两个线程同时发现
hash == 0并各自算一遍),不加锁,换取读取零开销 - 因为 String 不可变,一旦写入就不会变,缓存永远有效
JDK 版本对缓存的影响
底层存储变化没影响缓存逻辑,但影响计算路径:
- JDK 8 及之前:
value是char[],计算直接遍历 char 数组 - JDK 9 起:
value改为byte[],配合coder字段区分 Latin-1(单字节)和 UTF-16(双字节)编码 - Latin-1 字符串计算更快——每个字节直接当字符值用,不用转成 char;JVM 会自动选择最优路径
为什么这个缓存能放心用
关键在于 String 的三个硬约束:
-
不可变性:
value和coder都是final,内容永不改变 - 无外部可变状态:没有 setter、没有公开数组引用,无法绕过封装修改内容
-
哈希契约守得住:只要字符串内容不变,
hashCode()就一定返回相同值,满足 HashMap 等容器的前提
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










