java中对象相等要求equals与hashcode严格一致:equals为true时hashcode必相同,且二者须基于相同字段计算;重写equals需满足自反性、对称性、传递性、一致性及null安全。

Java 中对象相等的逻辑一致性,本质是 equals 和 hashCode 两个方法在语义和行为上必须严格对齐。不是“差不多一样”,而是契约式绑定:只要 equals 认为两个对象相等,它们的 hashCode 就必须相同;否则,集合类(如 HashMap、HashSet)会彻底失灵。
equals 定义“什么是相等”
它回答的是业务层面的问题:两个对象在逻辑上是否代表同一个东西?比如两个 User 对象,id 和 name 都相同,就该算“同一个用户”。但默认的 equals 只比较内存地址——这显然不符合大多数业务场景。
重写时必须守住五条底线:
- 自反性:x.equals(x) 一定为 true
- 对称性:x.equals(y) 为 true → y.equals(x) 也得为 true
- 传递性:x.equals(y) 且 y.equals(z) → x.equals(z) 必须成立
- 一致性:只要参与比较的字段没变,多次调用结果不能变
- 对 null 安全:任何非空对象调用 .equals(null) 必须返回 false
推荐写法:先用 if (obj == null || getClass() != obj.getClass()) return false; 拦住类型和空值,再用 Objects.equals(a, b) 安全比字段。
hashCode 是 equals 的“哈希签名”
它不定义相等,而是为哈希结构提供快速分组依据。你可以把它理解成“身份证编号的简码”:编号不同,人一定不同;编号相同,还得靠 equals 这张“身份证原件”来最终核验。
关键约束只有一条:如果 equals 返回 true,hashCode 必须返回相同值。违反它,后果直接可见:
- 放进 HashSet 的对象,后续调用 contains 找不到
- 作为 HashMap 的 key,put 进去后 get 不回来
- 对象看似“存在”,实则被散列到错误桶里,成了“幽灵数据”
二者必须用同一套字段计算
比如你用 id 和 email 判断 equals,那 hashCode 就只能基于 id 和 email 计算,漏掉一个或加进 createTime 都会破坏一致性。
安全做法是统一委托给 Objects.hash(id, email) ——它自动处理 null,生成分布合理的 int 值,避免手写 31 * x + y 公式出错。
字段修改后别放哈希集合
一旦对象加入 HashSet 或作为 HashMap 的 key,它参与 equals 和 hashCode 的字段就不能再改。改了之后,hashCode 变了,但对象还留在旧桶里,后续查找永远失败。
这不是 bug,是设计使然:哈希集合假设 key 是不可变的。若业务需要可变,要么用其他集合(如 ArrayList + 手动遍历),要么把关键字段设为 final。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











