定義hashcode時使用31係數的原因

2022-10-06 05:36:08 字數 1069 閱讀 1476

雜湊計算就是計算元素應該放在陣列的哪個元素裡。準確的說是放到哪個鍊錶裡面。按照j**a的規則,如果你要想將乙個物件放入hashmap中,你的物件的類必須提供hashcode方法,返回乙個整數值。比如string類就有如下方法:

public int hashcode()

bfbqtbe hash = h;

} return h;

}注意上面的for迴圈,有點搞吧?我來舉個例子,讓你很容易明白它在搞什麼名堂。比如有乙個字串「abcde」,採用31進製的計算方法來計算這個字串的總和,你會寫出下面的計算式子:

a*31^4+b*31^3+c*31^2+d*31^1+e*31^0.注意,這裡的a,b,c,d或者e指的是它們的ascii值。很有趣的迴圈,居然可以用來算n進製。這個迴圈可以抽出來單獨作為計算進製的好工具:

public static void main(string args) ;

system.out.println(calculate(2,a));

} private static int calculate(int radix,int a)排列。上面的輸出結果是1,符合01的真實值。

那麼為什麼選用31作為基數呢?先要明白為什麼需要hashcode.每個物件根據值計算hashcode,這個code大小雖然不奢求必須唯一(因為這樣通常計算會非常慢),但是要盡可能的不要重複,因此基數要盡量的大。另外,31*n可以被編譯器優化為

左移5位後減1,有較高的效能。其實選用31還是有爭議,參考這裡。

認為這個東西還是會導致較多的重複,應該用更大的數字。所以,或許將來j**a的實現中會有所變化。下面這篇文章介紹了兩個結論:

1.基數要用質數

質數的特性(只有1和自己是因子)能夠使得它和其他數相乘後得到的結果比其他方式更容易產成唯一性,也就是hash code值的衝突概率最小。

2.選擇31是觀測分布結果後的乙個選擇,不清楚原因,但的確有利。

另外,string.hashcode內部會快取第一次計算的值,因為這是乙個final(不可變)類,也就是string物件的內容是不會變的。這能夠在多次put到hashmap的場合提高效能,不過似乎用處不多。

總結

為什麼在定義hashcode時要使用31這個數呢?

public int hashcode hash h return h 該函式是我看的函式介面原始碼,為什麼要使用31這個數呢?其實上面的實現也可以總結成數數裡面下面這樣的公式 s 0 31 n 1 s 1 31 n 2 s n 1 原因如下 a.31是乙個素數,素數作用就是如果我用乙個數字來乘以這...

為什麼在定義hashcode時要使用31這個數呢?

public int hashcode hash h return h 該函式是我看的函式介面原始碼,為什麼要使用31這個數呢?其實上面的實現也可以總結成數數裡面下面這樣的公式 s 0 31 n 1 s 1 31 n 2 s n 1 原因如下 a.31是乙個素數,素數作用就是如果我用乙個數字來乘以這...

hashcode使用31作為乘法因子的原因小記

31是質子數中乙個 不大不小 的存在,如果你使用的是乙個如2的較小質數,那麼得出的乘積會在乙個很小的範圍,很容易造成雜湊值的衝突。而如果選擇乙個100以上的質數,得出的雜湊值會超出int的最大範圍,這兩種都不合適。而如果對超過 50,000 個英文單詞 由兩個不同版本的 unix 字典合併而成 進行...