定義hashcode時使用31系數(shù)的原因
散列計算就是計算元素應該放在數(shù)組的哪個元素里。準確的說是放到哪個鏈表里面。按照Java的規(guī)則,如果你要想將一個對象放入HashMap中,你的對象的類必須提供hashcode方法,返回一個整數(shù)值。比如String類就有如下方法:
public int hashCode() { int h = hash; int len = count; if (h == 0 && len > 0) { int off = offset; char val[] = value; for (int i = 0; i < len; i++) { h = 31*h + val[off++]; } hash = h; } return h; }
注意上面的for循環(huán),有點搞吧?我來舉個例子,讓你很容易明白它在搞什么名堂。比如有一個字符串“abcde”,采用31進制的計算方法來計算這個字符串的總和,你會寫出下面的計算式子:
a*31^4+b*31^3+c*31^2+d*31^1+e*31^0.注意,這里的a,b,c,d或者e指的是它們的ASCII值。很有趣的循環(huán),居然可以用來算N進制。這個循環(huán)可以抽出來單獨作為計算進制的好工具:
public static void main(String[] args) { int[] a={1,0}; System.out.println(calculate(2,a)); } private static int calculate(int radix,int[] a){ int sum = 0; for(int i=0;i<a.length;++i){ sum = sum*radix+a[i]; } return sum; }
靜態(tài)方法caculate接受radix作為進制基數(shù),數(shù)組a模擬要計算的進制的數(shù)字,只是注意表面順序需要一致。比如 01 二進制串,在數(shù)組中要按照{(diào)0,1}排列。上面的輸出結(jié)果是1,符合01的真實值。
那么為什么選用31作為基數(shù)呢?先要明白為什么需要HashCode.每個對象根據(jù)值計算HashCode,這個code大小雖然不奢求必須唯一(因為這樣通常計算會非常慢),但是要盡可能的不要重復,因此基數(shù)要盡量的大。另外,31*N可以被編譯器優(yōu)化為
左移5位后減1,有較高的性能。其實選用31還是有爭議,參考這里。
認為這個東西還是會導致較多的重復,應該用更大的數(shù)字。所以,或許將來Java的實現(xiàn)中會有所變化。下面這篇文章介紹了兩個結(jié)論:
1.基數(shù)要用質(zhì)數(shù)
質(zhì)數(shù)的特性(只有1和自己是因子)能夠使得它和其他數(shù)相乘后得到的結(jié)果比其他方式更容易產(chǎn)成唯一性,也就是hash code值的沖突概率最小。
2.選擇31是觀測分布結(jié)果后的一個選擇,不清楚原因,但的確有利。
另外,String.hashCode內(nèi)部會緩存第一次計算的值,因為這是一個final(不可變)類,也就是String對象的內(nèi)容是不會變的。這能夠在多次put到HashMap的場合提高性能,不過似乎用處不多。
總結(jié)
以上就是本文關(guān)于定義hashcode時使用31系數(shù)的原因的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:
《詳解hashCode()和equals()的本質(zhì)區(qū)別和聯(lián)系》
如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
相關(guān)文章
SpringBoot整合Caffeine實現(xiàn)本地緩存的實踐分享
緩存是提升系統(tǒng)性能的一個不可或缺的工具,通過緩存可以避免大部分重復的請求到數(shù)據(jù)庫層,減少IO鏈接次數(shù),提升整體的響應速率,本地緩存中比較常見的比如 Caffeine 緩存,這篇文章將結(jié)合具體的 Springboot 項目搭配 Caffeine 實現(xiàn)本地緩存的各種使用方式2024-07-07Spring?MVC DispatcherServlet處理請求過程示例詳解
這篇文章主要介紹了Spring?MVC?DispatcherServlet處理請求過程示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09java web實現(xiàn)網(wǎng)上手機銷售系統(tǒng)
這篇文章主要為大家詳細介紹了java web實現(xiàn)網(wǎng)上手機銷售系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-08-08springboot2如何集成ElasticSearch6.4.3
這篇文章主要介紹了springboot2如何集成ElasticSearch6.4.3問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07java實現(xiàn)ip地址與十進制數(shù)相互轉(zhuǎn)換
本文介紹在java中IP地址轉(zhuǎn)換十進制數(shù)及把10進制再轉(zhuǎn)換成IP地址的方法及實例參考,曬出來和大家分享一下2012-12-12Intellij Idea 多模塊Maven工程中模塊之間無法相互引用問題
這篇文章主要介紹了Intellij Idea 多模塊Maven工程中模塊之間無法相互引用問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-01-01