1. 程式人生 > >HashMap的長度為什麼要是2的n次方

HashMap的長度為什麼要是2的n次方




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