簡體   English   中英

如果我不想將我的對象用作哈希表中的鍵,為什么兩個相等的對象應返回相等的哈希碼?

[英]Why should two equal objects return equal hash codes if I don't want to use my object as a key in a hash table?

這就是Object.hashCode()的Java文檔所說的:

如果根據equals(Object)方法,兩個對象相等,則在兩個對象中的每個對象上調用hashCode方法必須產生相同的整數結果。

但是他們沒有解釋為什么兩個相等的對象必須返回相等的哈希碼。 為什么Oracle工程師決定覆蓋equals時必須覆蓋hashCode

equals的典型實現不調用hashCode方法:

@Override
public boolean equals(Object arg0) {
    if (this == arg0) {
        return true;
    }
    if (!(arg0 instanceof MyClass)) {
        return false;
    }
    MyClass another = (MyClass) arg0;
    // compare significant fields here
}

有效的Java(第二版)中,我讀到:

第9項:覆蓋等於時,始終覆蓋hashCode。

錯誤的常見來源是無法覆蓋hashCode方法。 您必須在覆蓋等於的每個類中覆蓋hashCode。 否則,將導致違反Object.hashCode的常規協定,這將阻止您的類與所有基於哈希的集合(包括HashMap,HashSet和Hashtable)一起正常運行。

假設我不需要將MyClass用作哈希表的鍵。 在這種情況下,為什么需要覆蓋hashCode()

當然,當您有一個僅由您自己編寫的小程序,並且每次使用外部lib時都檢查它不依賴hashCode()則可以忽略所有這些警告。 但是,隨着軟件項目的增長,您將使用外部庫,並且這些庫將依賴hashCode()並且您將浪費大量時間來尋找錯誤。 或者在較新的Java版本中,其他一些類也使用hashCode() ,您的程序將失敗。

因此,只需實施此規則並遵循此簡單規則,就會容易得多,因為現代IDE只需單擊一下即可自動生成equalshashCode

更新一個小故事 :在工作中,我們在許多類中也忽略了此規則,僅實現了所需的多數為equalscompareTo 有一天,會發生一些奇怪的事情,因為一個程序員在GUI中使用了Hash * -Class,而我們的對象沒有遵循此規則。 最后,學徒需要用equals搜索所有類,並必須添加相應的hashCode方法。

如文本所述,這違反了使用中的總合同。 當然,如果您從未在任何需要哈希碼的地方使用它,沒有人會強迫您實現它。

但是,如果將來有一天需要怎么辦? 如果其他開發人員使用了該類怎么辦? 這就是為什么必須同時執行這兩個合同的原因,因此不會造成混亂。

顯然,如果沒有人調用您的類的hashCode方法,則沒人會知道它與equals不一致。 您能保證在項目期間(包括維護年限),沒有人需要從列表中刪除重復的對象或將一些額外的數據與對象相關聯嗎?

您可能更安全地實現hashCode以便與equals保持一致。 並不是特別困難,始終返回0已經是有效的實現。

(盡管不要只返回0)

必須重寫hashCode以與equals一致的原因是因為使用hashCode的原因和方式。 哈希碼用作值的替代,以便在將鍵值映射到某些對象時,可以使用哈希來提供具有合理空間的近恆定查找時間。 當兩個值比較相等時(即,它們是相同的值),那么當它們用作哈希集合的鍵時,它們必須映射到相同的對象。 這就要求它們具有相同的哈希碼才能到達它們。

您必須適當地覆蓋hashCode因為該手冊指出您必須這樣做。 它說您必須這樣做,因為已經做出了這樣的決定:庫可以假定您滿足該合同,因此在使用您提供的值作為函數實現中的鍵時,它們(和您)可以具有哈希的性能優勢。

常見的用法表明,對於equals()compareTo() (如果要對MyClass實例進行排序)以及使用哈希表,都需要// compare significant fields here的邏輯。 因此,將此邏輯放入hashCode()並讓其他方法使用哈希碼是有意義的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM