JDK之HashMap中的indexFor(int h, int length)方法
今天看到了HashMap,發現其中有一個方法很奇怪,叫indexFor(int h, int length),這個方法返回的是某個hashcode對應到hash table的下標位置,程式碼是這麼實現的:
static int indexFor(int h, int length) {
return h & (length-1);
}
看了半天才搞懂為什麼這麼寫,其實HashMap中放資料的還是陣列,當往map裡put值時就是向陣列中新增資料,只不過資料的位置時根據put的key來計算的。之前學hashtable的時候計算位置都是用hashcode%length的。但是HashMap中卻不是這麼做的。
我們假設現在hashmap的length為16,第一個hashcode的值為7.,那麼根據上面的程式碼,計算過程應該是:
7&(16-1)
轉換成二進位制來計算就是:
0111
&
1111
計算的結果為111,也就是7,我們會發現這個值與7%16的結果是一致的。讓我們再測試一個hashcode為33。
二進位制的計算過程是:
100001
&
001111
計算結果為000001,這與33%16結果又是相同的。
經過幾次模擬計算可以發現,length-1的二進位制值中每一位都是1,並且HashMap中保證了map的長度永遠是2的N次方,而2的N次方-1的值的二進位制每一位都是1.。所以當我們拿hashcode的值來計算的時候,如果hashcode二進位制位數是小於等於length-1的二進位制位數,那麼與計算結果就是hashcode的值,如果前者位數大於後者位數,則與計算時會將多出來的位與0相與,則結果必然時0,這就導致超出位的值被省去了,身下的值也就是hashcode%llength的值了。至於為什麼不直接用hashcode%length,是因為位運算要比模運算快一些。
解釋到這裡應該已經清楚這行程式碼的意思了,在這裡不得不感嘆,JDK的作者水平還是高,想法已經不是在如何實現上了,而是怎麼實現效率更高。