跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

Java哈希契约教程:怎么同步重写hashCode与equals方法

必须同步重写equals和hashCode,否则破坏哈希契约:若equals为true则hashCode必须相同,否则HashMap等集合会查找不到、重复添加或丢失元素;二者字段需一致、顺序相同且稳定。 重写
equals
和
hashCode
必须同步进行,否则会破坏哈希契约,导致对象在
HashMap
、
HashSet
等集合中行为异常——比如明明相等的对象查不到、重复添加、甚至集合“丢失”元素。 为什么必须一起重写? Java 规定:如果两个对象通过
equals
判断为
true
,那么它们的
hashCode
值也必须相同。这是哈希集合(如
HashMap
)正常工作的前提:
HashMap
先用
hashCode
定位桶(bucket),再用
equals
在桶内精确比对; 若
equals
返回
true
但
hashCode
不同 → 两个对象被散列到不同桶 →
get()
或
contains()
找不到; 若只重写
hashCode
不重写
equals
→ 默认使用
Object.equals
(基于内存地址),逻辑不一致,同样出错。 重写时的关键原则 确保语义一致、稳定、高效: 一致性 :只要用于比较的字段没变,多次调用
hashCode
必须返回相同值; 对称性 :若
a.equals(b)
为
true
,则
b.equals(a)
也必须为
true
; 传递性与非空性 :
equals
方法不能对
null
抛
NullPointerException
,推荐用
Objects.equals(a, b)
安全比较; 只用“业务关键字段”参与计算 :和
equals
判定逻辑完全一致的字段,才应参与
hashCode
计算(例如
id
和
name
,而不是
createTime
或临时缓存字段)。 标准写法示例(JDK 7+ 推荐) 以一个简单的
User
类为例: Eclipse导入Android或其他的JAVA项目的正确方法 WORD版 本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看 下载 立即学习 “ Java免费学习笔记(深入) ”;
public class User { private final String id; private final String name; private int age; // 注意:若 age 参与 equals,则必须参与 hashCode;若不参与,就别比它 public User(String id, String name) { this.id = id; this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return Objects.equals(id, user.id) && Objects.equals(name, user.name); } @Override public int hashCode() { return Objects.hash(id, name); // 自动处理 null,顺序必须和 equals 中一致 } }
注意 :
Objects.hash(...)
内部按参数顺序调用各字段的
hashCode
,所以字段顺序要和
equals
中的比较顺序严格一致;若字段可能为
null
,
Objects.equals
和
Objects.hash
都能安全处理。 常见错误与避坑提醒 重写了
equals
却忘了
@Override
注解 → 编译器不报错,但实际没覆盖父类方法; 在
hashCode
中用了可变字段(如普通
age
字段且未声明
final
),对象放入
HashSet
后修改该字段 →
hashCode
改变 → 桶位置失效 → 无法被找到; 用随机数、当前时间、数据库自增 ID(未持久化前)等不稳定值参与
hashCode
计算; 在
equals
中比较了子类特有字段,但父类的
hashCode
没覆盖 → 违反对称性或哈希契约。

相关文章