HashMap的長度為什麼要是2的n次方
阿新 • • 發佈:2019-02-20
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 00113
& 0000 10008
= 0000 00000
0000 00102
& 0000 10008
= 0000 00000
-------------------------------------------------------------
0000 00113
& 0000 01117
= 0000 00113
0000 00102
& 0000 01117
= 0000 00102
當然如果不考慮效率直接求餘即可(就不需要要求長度必須是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