class Name {
String firstname, secondname;
// 構造器、getter、toString...
@Override
public boolean equals(Object obj) {
if (obj instanceof Name) return true; // 錯誤:任意 Name 都相等
return super.equals(obj);
}
@Override
public int hashcode() { // 錯誤:方法名小寫,未重寫 hashCode()
return firstname.hashCode();
}
}
// 測試
Set<Object> c = new HashSet<>();
c.add(new Name("uzi", "omg"));
System.out.println(c.remove(new Name("uzi", "omg"))); // 輸出 false,對象未刪除
return true 導致**所有 Name 實例互相相等**,違反「自反性、對稱性、傳遞性」。hashcode() 小寫,**未覆寫 Object.hashCode()**,默認返回對象地址哈希。a.equals(b) == true ⇒ a.hashCode() == b.hashCode()。此處 equals 恒真,但 hashCode 不同 → **HashSet 無法定位桶位**,remove 失敗。class Name {
private String firstname, secondname;
// 構造器、getter...
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Name name = (Name) o;
return Objects.equals(firstname, name.firstname) &&
Objects.equals(secondname, name.secondname);
}
@Override
public int hashCode() { // ★ 大寫 C
return Objects.hash(firstname, secondname);
}
}
HashSet/HashMap 存儲邏輯:
key.hashCode() 確定桶位索引。equals() 比較。hashCode() 不同,**根本進不了同一桶**,equals() 永遠不會被調用。Name n1 = new Name("uzi", "omg");
Name n2 = new Name("uzi", "omg");
System.out.println(n1.equals(n2)); // true
System.out.println(n1.hashCode()); // 如 123456
System.out.println(n2.hashCode()); // 必須也是 123456
System.out.println(n1 == n2); // false (不同對象)
Source → Generate hashCode() and equals(),IDEA Alt+Insert → equals() and hashCode()。HashSet remove 返回 false,**99% 是 equals/hashCode 契約違反**。檢查:1. hashCode 方法名大寫 C 2. 邏輯一致性 3. 用不可變字段 4. 用 IDE 自動生成。修正後 c.remove(new Name("uzi","omg")) 返回 true,集合正常維護。