选质数(尤其是31)作乘子,因其与多数整数互质、分布均匀,可降低哈希碰撞;31还被JVM优化为位移减法运算,提升性能。

在 Java 中重写 hashCode 时,用质数(如 31)做乘法累加,是《Effective Java》推荐的标准做法,核心在于利用质数的数学特性——与大多数整数互质、分布更均匀,能有效打散字段组合后的哈希值,降低碰撞概率。
为什么选质数(尤其是 31)?
质数作为乘子可减少因字段值规律性(比如连续 ID、相同字符串前缀)导致的哈希值重复。31 被广泛采用,不仅因为它是质数,还因为它能被 JVM 优化为位移和减法:31 * i == (i ,计算高效。其他常用质数还有 37、41、101,只要避免与常见字段取值周期产生公因子即可。
多字段组合的正确写法
按字段声明顺序,逐个参与计算,初始值通常设为 1(非 0,避免首字段为 0 时整个结果为 0):
- 对每个字段
f:先获取其规范哈希值(f == null ? 0 : f.hashCode()) - 用质数乘当前结果,再加该字段哈希值:
result = result * 31 + fHash - 基本类型直接用对应包装类的
hashCode()(如Integer.hashCode(i)),或用Objects.hash(...)简化
一个典型示例
假设类有 String name、int age、boolean active 三个字段:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
@Override
public int hashCode() {
int result = 1; // 初始值
result = 31 * result + (name == null ? 0 : name.hashCode());
result = 31 * result + age;
result = 31 * result + (active ? 1 : 0);
return result;
}等价于使用 Objects.hash(name, age, active),它内部正是按此逻辑实现。
避开常见陷阱
不要忽略 null 安全;不要对浮点数直接用 floatToIntBits 或 doubleToLongBits 再哈希;不要把无关字段(如临时缓存、线程局部变量)纳入计算;字段顺序要与 equals 中比较顺序严格一致,否则违反契约。

















