java 改寫hashcode hashcode用法 - hashCode方法的最佳實現




10 Answers

最好的實現? 這是一個難題,因為它取決於使用模式。

幾乎所有的情況都是在Josh Bloch的第8條(第二版)中的Effective Java中提出的。 最好的辦法是在那裡查看它,因為作者解釋了為什麼這種方法是好的。

簡短的版本

  1. 創建一個int result並分配一個非零值。

  2. 對於equals()方法中測試的每個字段 f ,通過以下公式計算散列碼c

    • 如果字段f是一個boolean :calculate (f ? 0 : 1) ;
    • 如果字段f是一個bytecharshortint :calculate (int)f ;
    • 如果字段f是一個long :calculate (int)(f ^ (f >>> 32)) ;
    • 如果字段f是一個float :calculate Float.floatToIntBits(f) ;
    • 如果字段f是double :則計算Double.doubleToLongBits(f)並像每個long值一樣處理返回值;
    • 如果字段f是一個對象 :使用hashCode()方法的結果,或者如果f == null ,則使用0;
    • 如果字段f是一個數組 :將每個字段視為單獨的元素並以遞歸方式計算散列值,並按照下面所述組合值。
  3. 結合哈希值cresult

    result = 37 * result + c
    
  4. 返回result

這應該會導致散列值在大多數使用情況下的正確分佈。

hashcode中文 equals用法

我們如何決定集合的hashCode()方法的最佳實現(假設equals方法已被正確覆蓋)?




最好使用Eclipse提供的功能,它的功能非常出色,您可以投入精力和精力開發業務邏輯。




首先確保equals是正確實現的。 從IBM DeveloperWorks的文章

  • 對稱性:對於兩個引用,a和b,a.equals(b)當且僅當b.equals(a)
  • 反身性:對於所有非空引用,a.equals(a)
  • 傳遞性:如果a.equals(b)和b.equals(c),則a.equals(c)

然後確保他們與hashCode的關係尊重聯繫人(來自同一篇文章):

  • 與hashCode()的一致性:兩個相等的對象必須具有相同的hashCode()值

最後,一個好的散列函數應該力求接近理想的散列函數







只需填寫其他更詳細的答案(以代碼形式)即可:

如果我考慮how-do-i-create-a-hash-table-in-java ,特別是jGuru FAQ條目 ,我相信其他一些判斷哈希代碼的標準是:

  • 同步(算法是否支持並發訪問)?
  • 失敗安全迭代(算法是否檢測迭代過程中發生變化的集合)
  • 空值(散列碼是否支持集合中的空值)



@約8:那裡有一個非常嚴重的錯誤。

Zam obj1 = new Zam("foo", "bar", "baz");
Zam obj2 = new Zam("fo", "obar", "baz");

相同的哈希碼

你可能想要類似的東西

public int hashCode() {
    return (getFoo().hashCode() + getBar().hashCode()).toString().hashCode();

(你現在可以在Java中直接從int獲得hashCode嗎?我認為它有一些自動生成功能。如果是這種情況,請跳過toString,這很醜陋。)







我更喜歡使用來自類對象的Google Collections庫中的實用程序方法,這有助於我保持代碼清潔。 通常情況下, equalshashcode方法是由IDE的模板創建的,所以它們並不干淨。




這裡是另一個JDK 1.7+方法演示,其中包含超類邏輯。 我認為它很適合Object class hashCode(),純JDK依賴性和無需額外手動工作。 請注意Objects.hash()是空的寬容。

我沒有包含任何equals()實現,但實際上你當然需要它。

import java.util.Objects;

public class Demo {

    public static class A {

        private final String param1;

        public A(final String param1) {
            this.param1 = param1;
        }

        @Override
        public int hashCode() {
            return Objects.hash(
                super.hashCode(),
                this.param1);
        }

    }

    public static class B extends A {

        private final String param2;
        private final String param3;

        public B(
            final String param1,
            final String param2,
            final String param3) {

            super(param1);
            this.param2 = param2;
            this.param3 = param3;
        }

        @Override
        public final int hashCode() {
            return Objects.hash(
                super.hashCode(),
                this.param2,
                this.param3);
        }
    }

    public static void main(String [] args) {

        A a = new A("A");
        B b = new B("A", "B", "C");

        System.out.println("A: " + a.hashCode());
        System.out.println("B: " + b.hashCode());
    }

}



當組合散列值時,我通常使用boost c ++庫中使用的組合方法,即:

seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);

這在確保均勻分佈方面做得相當好。 有關此公式如何工作的一些討論,請參閱文章: boost :: hash_combine中的幻數

http://burtleburtle.net/bob/hash/doobs.html討論了不同的哈希函數




Related