一、基本概念
-
equals()
-
Object类中的原始实现是比较内存地址(
this == obj
) -
包装类(String/Integer等)已重写为内容比较
-
重写必须遵守五大原则:对称性、反射性、传递性、一致性、非空性
-
hashCode()
-
Object类中的native方法,默认与对象地址相关
-
包装类已重写为基于内容的哈希计算
-
String类的哈希计算:
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
二、两者关系
-
强制关系
-
equals()返回true → hashCode()必须相同
-
hashCode()不同 → equals()必须返回false
-
非强制关系
-
hashCode()相同,equals()可能相同也可能不同(哈希碰撞)
-
equals()返回false,hashCode()可能相同也可能不同
三、在集合中的应用
-
HashSet/HashMap判断元素是否相等的流程:
1. 先比较hashCode - 不同 → 直接判定为不同对象 - 相同 → 2. 再比较equals - 不同 → 判定为不同对象(哈希碰撞) - 相同 → 判定为相同对象
-
重要结论:
-
只重写equals()会导致相同对象被存入不同哈希桶
-
只重写hashCode()会导致集合无法正确识别相等对象
-
必须同时正确重写这两个方法!
四、图示说明
equals()比较
┌───────────┬───────────┐
│ true │ false │
├───────────┼───────────┤
│ hashCode │ hashCode │
│ 必须相同 │ 可能相同 │
│ │ 可能不同 │
└───────────┴───────────┘
五、要点
-
重写equals()必须同时重写hashCode()
-
两个方法必须基于相同的字段集合
-
使用Objects工具类可简化实现并保证null安全
-
好的哈希算法应尽量减少碰撞概率