哈希一致性需 hashcode 与 equals 共同保证:相等对象必须有相同哈希码;二者须同步重写、字段一致、顺序一致;推荐用 objects.hash() 安全生成;对象状态须稳定,避免可变字段影响查找。

哈希一致性不是靠 hashCode 单独保证的,而是由 hashCode 和 equals 共同遵守约定来实现的。核心就一条:相等的对象必须有相同的哈希码。
必须同时重写 equals 和 hashCode
只改其中一个会直接破坏哈希表行为:
- 重写了
equals却不重写hashCode→ 逻辑相等的对象可能被散列到不同桶里,HashMap.get()找不到,HashSet.contains()返回false - 重写了
hashCode却没改equals→ 默认用内存地址比较,两个内容一样的对象仍被视为不同,无法去重 - 两个方法用的字段不一致(比如
equals比较了 name 和 age,hashCode只用了 name)→ 相等对象哈希值不同,同样查不到
hashCode 的计算要严格基于 equals 所用字段
哪些字段参与,怎么参与,都有明确要求:
- 只包含
equals方法中实际用于判断相等的字段,多一个、少一个都不行 - 顺序必须和
equals中的比较顺序一致(尤其影响对称性) - 引用类型用
Objects.hashCode(field)或直接传给Objects.hash(...),它自动处理null - 数组字段要用
Arrays.hashCode(arr),不能直接调用arr.hashCode() - 浮点数用
Float.floatToIntBits(f)或Double.doubleToLongBits(d),避免-0.0和0.0哈希不同
用 Objects.hash() 是最稳妥的选择
手写 31 * x + y 容易出错,JDK 提供的工具已覆盖所有边界:
- 一行搞定:
return Objects.hash(name, age, tags); - 自动判空、安全转换、合理组合,语义清晰
- 比 IDE 自动生成更可靠——IDE 有时会误加
transient字段或日志器,得手动删 - Lombok 的
@Data默认生成没问题,但若类里已有自定义equals却没配@EqualsAndHashCode,就会不一致
对象状态必须稳定
哈希值一旦算出来,就不能变,否则存进集合后就“找不到了”:
- 优先用
final字段,从源头杜绝修改 - 如果字段可变,对象放入
HashSet或作为HashMap的 key 后,就不要再改这些字段 - 绝对不要在
hashCode里用随机数、时间戳、内存地址等不稳定值 - 不可变类可考虑缓存哈希值:
private int cachedHash;,首次计算后复用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











