首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java HashSet remove 返回 true/false 差異:equals/hashCode 契約與值類型 vs 引用類型

     編輯:程式設計綜合問答

現象代碼

Set<Object> set = new HashSet<>();
set.add("hello");
set.add(new Name("lu", "dongdong"));
set.add(new Integer(100));

System.out.println(set.remove(new Integer(100))); // true
System.out.println(set.remove(new Name("lu", "dongdong"))); // false

核心原因

類型equals 實現hashCode 實現new 實例是否相等
Integer (包裝類) 比較 數值 基於數值計算 是:new Integer(100).equals(new Integer(100)) == true
String 比較 字符序列 基於字符計算 是 (字面量池/內容相同)
Name (自定義類,未重寫) 繼承 Object.equals → 比較引用地址 繼承 Object.hashCode → 基於地址 否:new Name(...) 產生不同對象,引用不等

HashSet.remove 內部邏輯

public boolean remove(Object o) {
    int hash = hash(o);
    for (Node<E> e = table[hash & (table.length-1)]; e != null; e = e.next) {
        if (e.hash == hash && (e.key == o || o.equals(e.key))) { // 關鍵:調用 equals
            removeNode(hash, e.key, null, false, true);
            return true;
        }
    }
    return false;
}

刪除時會遍歷桶,**調用 o.equals(e.key)** 比較。Integer 重寫了 equals 比較值,Name 未重寫比較引用 → 導致找不到匹配元素。

修正 Name 類:重寫 equals/hashCode

class Name {
    private String firstName, lastName;

    public Name(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @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(lastName, name.lastName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstName, lastName);
    }

    // toString 保持不變
}

重寫後:set.remove(new Name("lu", "dongdong")) 返回 true。

最佳實踐:IDE 自動生成 / Lombok / Record (Java 16+)

// Lombok
@Data // 含 @EqualsAndHashCode
class Name {
    private String firstName, lastName;
}

// Java 16+ Record (隱式 final、equals/hashCode/toString 自動實現)
record Name(String firstName, String lastName) {}

總結

  1. 值類型 (Integer, String, LocalDate 等) 重寫 equals/hashCode 比較內容,new 實例可相等。
  2. 引用類型 默認比較身份 (地址),放入 HashSet/HashMap 作為鍵/元素時,**必須重寫 equals/hashCode** 基於業務鍵比較。
  3. HashSet.remove、contains、Map.get 都依賴 equals 契約。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved