请解释 Java 中 hashCode 与 equals 方法之间的约束关系,以及违反这些约束可能带来的后果。
考察说明
考查对 Object 类中 hashCode 与 equals 契约的理解及其在哈希集合中的应用。
回答思路
- 【回答框架 1】equals 用于判断对象逻辑相等,默认实现是比较引用。hashCode 返回对象的哈希码,用于哈希表快速定位。两者必须遵守约定:如果两个对象 equals 相等,则它们的 hashCode 必须相等;反之不要求,但哈希码相等时 equals 不一定相等。
- 【回答框架 2】当对象作为 HashMap 或 HashSet 的键时,先通过 hashCode 定位到哈希桶,再用 equals 在桶内比较。若 equals 相等但 hashCode 不等,对象会散落在不同桶中,导致无法正确查找;若覆盖 equals 而不覆盖 hashCode,会破坏上述约定。
- 【回答框架 3】覆盖 equals 时需满足自反性、对称性、传递性、一致性和非空性等原则,同时必须覆盖 hashCode。常见的实现是基于关键字段生成哈希码,例如使用 Objects.hash 方法,确保相等对象生成相同的哈希码。
- 【回答框架 4】实际开发中,若自定义类需要作为集合的键或用于去重,应同时重写这两个方法,并保持字段一致。若仅用于逻辑比较而不放入哈希结构,可以只重写 equals,但为安全起见仍建议同时重写。
- 【关键点 1】equals 相等则 hashCode 必相等,这是硬性约定。
- 【关键点 2】hashCode 相等时 equals 不一定相等,即可能冲突。
- 【关键点 3】覆盖 equals 而不覆盖 hashCode 会导致哈希集合中的对象无法被正确查找。
- 【关键点 4】hashCode 计算应使用与 equals 相同的字段,保证一致性。
- 【关键点 5】哈希码分布均匀可减少冲突,提升哈希表性能。
- 【易错点 1】误以为 hashCode 相等则对象相等,导致用哈希码直接比较对象。
- 【易错点 2】覆盖 equals 后忘记覆盖 hashCode,导致对象放入 HashSet 后无法删除或查找。
- 【易错点 3】使用可变字段参与 hashCode 计算,对象放入集合后修改字段会导致哈希码变化,造成集合中数据丢失。