重写 hashcode 和 equals 方法必须仅基于业务关键属性(如 user 的 username 和 email),排除 id 等非业务字段;需满足对称性、传递性等契约,用 objects.equals 和 objects.hash 实现,并确保两者字段完全一致。

重写 hashCode 和 equals 方法,核心是**只基于对象中用于逻辑相等判断的封装属性(即业务上决定“两个对象是否相同”的字段)来实现**,其他属性(如数据库ID、临时状态、缓存字段等)不应参与比较和哈希计算。
只用“业务关键属性”参与 equals 和 hashCode
例如一个 User 类,业务上认为“姓名 + 邮箱”唯一确定一个用户,那么即使有 id 或 createTime 字段,也不该放进 equals 和 hashCode:
-
错误做法:把所有字段(包括自增主键
id)都参与比较 → 新建但未保存的对象永远不等于已存对象,导致集合查找失败 -
正确做法:只选不可变或业务语义上决定“同一性”的字段,如
username和email
equals 方法要满足对称性、传递性、一致性等契约
手写时注意几个关键点:
- 先判
null和类型(instanceof或getClass(),推荐后者避免子类误判) - 字段比较用
Objects.equals(a, b),自动处理null安全 - 不要用
==比字符串或包装类,必须用.equals() - 如果用了
getClass()判类型,子类重写equals后父类对象与子类对象一定不等
hashCode 必须与 equals 保持一致
只要 equals 返回 true,两个对象的 hashCode 就必须相同。常用写法:
- 用
Objects.hash(field1, field2, ...)—— 简洁、安全、符合规范 - 手动计算可用
31 * result + Objects.hashCode(field),但没必要重复造轮子 - 确保参与
hashCode的字段,和equals中实际比较的字段完全一致
IDE 自动生成更可靠,但要会检查和删减
IntelliJ 或 Eclipse 生成的代码默认包含所有字段,你需要手动删掉不该参与的字段(比如 id、version、transient 字段、懒加载代理等):
- 生成后打开方法,逐个核对字段是否属于“业务身份标识”
- 若字段可能为
null,确认Objects.equals和Objects.hashCode已妥善处理 - 若类后续新增关键属性,记得同步更新这两个方法(或改用 Lombok 的
@EqualsAndHashCode并指定include)
不复杂但容易忽略:只要改了影响相等判断的字段,就得重新审视 equals 和 hashCode 是否还合理。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











