HashMap 索引計算


 

從HashMap源碼中,可以看到求容器下標值的方法,有兩步,首先通過key值計算hash,然后用hash計算下標:

  計算hash:

  return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

 

  計算下標,其下標值為:(n-1) & hash

 n = (tab = resize()).length;

p = tab[i = (n - 1) & hash]

  即,是通過key的hash值和容器的大小減1,兩者進行與運算,獲取容器數組下標。這里使用與運算,其實蘊含了一個隱藏條件,即數組的大小n,必須是2的n次方,否則,計算出來的下標值i是無法覆蓋這個范圍[0, n-1]的。

  舉個例子,假設兩種情況,一種容器大小為10,不是2的冪,另外一種容器大小為16,剛好是2的4次方。

  則,對於第一種,n-1= 9, 二進制表示為 1001,任何值與該值進行與運算,都無法改變中間的兩個0,只能改變首尾的兩個1,因此結果范圍就縮小了一倍

  而,對於第二種,n-1=15,二進制表示為 1111,該值與其他值與運算后,可以覆蓋范圍[0, 15],而這個范圍剛好是數組的大小,因此只要hash值均勻分布,結果也是均勻的。

  實際上,只要數組大小是2的冪,則 (n-1) & hash 的結果等效於: hash % (n-1);即與運算、求余運算通過這個前提,實現了等效。

  而計算機中,與運算和求余運算,兩個計算的效率肯定是前者更好。因為與運算,是直接對位進行邏輯與操作,屬於cpu的底層支持的基礎邏輯操作,但是求余運算可不是,應該是需要額外的算術運算單元支持的。可能這就是把數組大小規定為2的冪的原因之一,提高運算效率。

 

附注:這里額外補充一點,即HashMap的擴容機制,涉及到的參數有容器大小,負載因子,當實際數據的數量,超過兩者的乘積時,就觸發擴容,直接放大一倍。比如原本容器大小為16,負載因子為0.75(默認的),當放入的數據個數從12變為13時,則容器大小擴大為32. 擴容時,原本元素的位置也會發生改變,但是這種改變是有規律的,有一些是不變,而發生改變的,則剛好都是在原來數組索引的基礎上,加上擴大的數量值(在該例子中就是加上16)。

  這個我沒有看源碼,是直接根據上面的索引計算方式推斷出來的,試驗結果也證明確實如此。

  擴容前:

  

 

 

擴容后:

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM