前提:
偶然的機會看到了大神的一篇博客,介紹的是hashCode()方法里為什么要用31這個數字作為生成hashCode的乘數。hashCode我在比較自定義類時曾經用到過 - 由於java默認比較的是類的地址值,每個對象一定是不同的,所以重寫了hashCode()和equals()方法
,這樣就會先根據類里的屬性生成hashCode,如果生成的hashCode值相同,則在使用equals()比較屬性的值。兩者都相同則認為這兩個對象相等。當是就對hashCode的生成很好奇,自己看了下源碼也是懵懵懂懂。這下終於可以搞清楚了,開森,感謝大佬!
hashCode()方法的源碼:
原因一:更少的乘積結果沖突
31是質子數中一個“不大不小”的存在,如果你使用的是一個如2的較小質數,那么得出的乘積會在一個很小的范圍,很容易造成哈希值的沖突。而如果選擇一個100以上的質數,得出的哈希值會超出int的最大范圍,這兩種都不合適。而如果對超過 50,000 個英文單詞(由兩個不同版本的 Unix 字典合並而成)進行 hash code 運算,並使用常數 31, 33, 37, 39 和 41 作為乘子,每個常數算出的哈希值沖突數都小於7個(國外大神做的測試),那么這幾個數就被作為生成hashCode值得備選乘數了。
原因二:31可以被JVM優化
JVM里最有效的計算方式就是進行位運算了:
* 左移 << : 左邊的最高位丟棄,右邊補全0(把 << 左邊的數據*2的移動次冪)。
* 右移 >> : 把>>左邊的數據/2的移動次冪。
* 無符號右移 >>> : 無論最高位是0還是1,左邊補齊0。
所以 : 31 * i = (i << 5) - i(左邊 31*2=62,右邊 2*2^5-2=62) - 兩邊相等,JVM就可以高效的進行計算啦。。。
ps:以前家里人老說學號數理化,走遍全天下。貌似很有道理^_^