HashMap為了存取高效,要盡量較少碰撞,就是要盡量把數據分配均勻,每個鏈表長度大致相同,這個實現就在把數據存到哪個鏈表中的算法;
這個算法實際就是取模,hash%length,計算機中直接求余效率不如位移運算,源碼中做了優化hash&(length-1),
hash%length==hash&(length-1)的前提是length是2的n次方;
為什么這樣能均勻分布減少碰撞呢?2的n次方實際就是1后面n個0,2的n次方-1 實際就是n個1;
例如長度為9時候,3&(9-1)=0 2&(9-1)=0 ,都在0上,碰撞了;
例如長度為8時候,3&(8-1)=3 2&(8-1)=2 ,不同位置上,不碰撞;
其實就是按位“與”的時候,每一位都能 &1 ,也就是和1111……1111111進行與運算
0000 0011 3
& 0000 1000 8
= 0000 0000 0
0000 0010 2
& 0000 1000 8
= 0000 0000 0
-------------------------------------------------------------
0000 0011 3
& 0000 0111 7
= 0000 0011 3
0000 0010 2
& 0000 0111 7
= 0000 0010 2
當然如果不考慮效率直接求余即可(就不需要要求長度必須是2的n次方了);
有人懷疑兩種運算效率差別到底有多少,我做個測試:
- /**
- *
- * 直接【求余】和【按位】運算的差別驗證
- */
- public static void main(String[] args) {
- long currentTimeMillis = System.currentTimeMillis();
- int a=0;
- int times = 10000*10000;
- for (long i = 0; i < times; i++) {
- a=9999%1024;
- }
- long currentTimeMillis2 = System.currentTimeMillis();
- int b=0;
- for (long i = 0; i < times; i++) {
- b=9999&(1024-1);
- }
- long currentTimeMillis3 = System.currentTimeMillis();
- System.out.println(a+","+b);
- System.out.println("%: "+(currentTimeMillis2-currentTimeMillis));
- System.out.println("&: "+(currentTimeMillis3-currentTimeMillis2));
- }
結果:
783,783
%: 359
&: 93