equals(Object):默認比較引用地址(this == obj)。hashCode():native 方法,通常基於對象地址生成。equals(true) ⇒ hashCode() 必相等;hashCode() 相等 ⇏ equals(true)。集合框架(HashSet、HashMap、Hashtable)依賴雙重校驗:
hashCode() 定位桶(O(1))。equals() 精確匹配。若僅重寫 equals() 不重寫 hashCode(),邏輯相等對象可能落入不同桶,導致 Set 重複、Map 查不到。
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return id == person.id && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name); // JDK 7+ 推薦
// 手寫版:31 * id + (name == null ? 0 : name.hashCode());
}
| 場景 | 現象 | 原因 |
|---|---|---|
| String s1=new("a"), s2=new("a") | s1==s2 false,s1.equals(s2) true | String 重寫 equals 比內容,hashCode 同算法 |
| 自定義類未重寫 hashCode | HashSet 添加兩個邏輯相等對象均保留 | 繼承 Object.hashCode() 基於地址,落入不同桶 |
| hashCode 常量返回 1 | 所有對象進同一桶,退化為鏈表 O(n) | 滿足契約但效能極差 |
add(element)
│
├─► hashCode() → 定位桶
│
├─► 桶為空 → 直接存入 ✓
│
└─► 桶非空 → 遍歷桶內 Entry
│
├─► hashCode() 不等 → 繼續下一個
│
└─► hashCode() 相等 → equals() 比較
│
├─► true → 視為重複,不存入 / 覆蓋 value
│
└─► false → 繼續下一個
Set、Map key)極其依賴契約正確性。「equals 比業務鍵,hashCode 同算法;
兩方法必須同增減,緩存哈希慎重寫。」