题目
深入理解Java中的equals()和hashCode()方法
信息
- 类型:问答
- 难度:⭐⭐
考点
对象相等性,哈希原理,集合框架,方法重写规范
快速回答
核心要点:
- 重写
equals()时必须同时重写hashCode() - 两个对象
equals()相等时,其hashCode()必须相等 - 哈希冲突时不同对象可能有相同哈希值
- 违反规则会导致
HashMap、HashSet等集合行为异常
1. 原理说明
Java中对象相等性判断基于两个层次:
- equals():逻辑相等性(默认使用
==比较内存地址) - hashCode():为对象生成哈希码,用于哈希表快速定位
在哈希集合(如HashMap)中,先通过hashCode()定位桶位置,再用equals()精确匹配。若违反以下契约会导致集合行为异常:
强制契约:
- 两个对象
equals()相等 → 其hashCode()必须相等 - 两个对象
equals()不相等 →hashCode()可以相等(哈希冲突)
2. 代码示例
public class Person {
private String name;
private int age;
// 构造方法等省略
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
// 使用JDK提供的Objects工具类
return Objects.hash(name, age);
}
}
3. 最佳实践
- 字段选择:使用
equals()中比较的相同字段计算哈希码 - 工具类:优先使用
Objects.hash(field1, field2...)简化实现 - 不可变字段:避免使用可变字段计算哈希码(否则集合中元素会"消失")
- 性能优化:对于复杂对象,可缓存哈希码(需确保对象不可变)
4. 常见错误
| 错误类型 | 后果 | 示例 |
|---|---|---|
| 只重写equals() | HashMap.get()可能返回null | 两个equals相等的对象在HashMap中被存到不同桶 |
| 使用可变字段 | 集合元素"丢失" | 对象存入HashSet后修改参与哈希计算的字段 |
| 忽略null安全 | NullPointerException | 未处理字段为null的情况 |
5. 扩展知识
- 哈希冲突处理:Java 8+的HashMap使用链表+红黑树,当链表长度>8时转树
- Lombok注解:
@EqualsAndHashCode可自动生成合规实现 - IdentityHashMap:特殊Map使用
==代替equals(),不依赖hashCode - 性能影响:差的hashCode实现(如所有实例返回1)会使HashMap退化为链表