HashMap在JDK1 8如何確定初始化容量

2021-09-12 12:58:55 字數 2253 閱讀 7187

大家都知道hashmap是採用的懶載入機制,也就是說在你執行new hashmap()的時候,構造方法並沒有在構造出hashmap例項的同時也把hashmap例項裡所需的陣列給初始化出來。

那麼什麼時候才去初始化裡面的陣列呢?答案只有在第一次需要用到這個陣列的時候才會去初始化它,就是在你往hashmap裡面put元素的時候。

而初始化陣列時,它的容量是怎麼確定的呢?有兩種情況:

第一種是你在構造hashmap例項的時候,呼叫的是無參建構函式,此時預設的陣列初始化長度就是16,在後續put元素初始化陣列時生效。

public

hashmap()

第二種情況,則是你調的是帶了陣列容量引數的建構函式:

public

hashmap

(int initialcapacity)

或者

public

hashmap

(int initialcapacity,

float loadfactor)

當然可以看出上面那個構造方法裡面執行的是this(initialcapacity, default_load_factor),實際也就是下乙個構造方法。

當你呼叫帶參構造器初始化乙個指定陣列容量的hashmap時,構造器會根據你輸入的引數重新計算得到乙個hashmap初始化陣列之後陣列實際的長度,這個值也是會在put元素初始化陣列時起作用。計算的邏輯在tablesizefor(int cap)中:

static

final

inttablesizefor

(int cap)

這個方法的作用是什麼呢,比如你輸入的容量引數為a,返回值為b,那麼a與b的關係如下:

1、b大於或等於a

2、b為最接近a的乙個2的n次方

舉幾個栗子就是:

1、輸入1,返回1(2^0)

2、輸入2,返回2(2^1)

3、輸入3,返回4(2^2)

4、輸入4,返回4(2^2)

5、輸入5,返回8(2^3)

依此類推~

那麼方法體是如何實現這些邏輯的呢,從**中可以看到大部分**都是在做無符號右移(>>>)和位或(|),這裡其實都是在做2進製的位操作,描述起來比較困難,還是來舉幾個栗子吧,假如你輸入的引數為35:

int n = cap - 1;

那麼n = 34;

那麼34對應的2進製編碼為:100010

n | n >>> 1等同於n = n | n >>> 1,就是34與34右移一位之後做位或操作:

得到的二進位制是110011,轉化為10進製是51;

接下來n |= n >>> 2;

得到的二進位制是111111,轉化為10進製是63;

接下來是 n |= n >>> 4;

得到的二進位制也是111111,轉化為10進製是63;

接下來是 n |= n >>> 8;

得到的二進位制也是111111,轉化為10進製是63;

接下來是 n |= n >>> 16;

得到的二進位制也是111111,轉化為10進製是63;

最終 return (n < 0) ? 1 : (n >= maximum_capacity) ? maximum_capacity : n + 1這一行,

先判斷n是否大於0:

1、不大於0返回1

2、否則再判斷n是否大於定義的最大容量(1>>30):

1:若大於1>>30,則返回1>>30

2:否則返回n+1

實際最終這個方法,就是利用移位與位或運算,將n-1得到的值轉成2進製之後,從1的最高位開始將低位全部轉化為1,再加1之後就可以得到乙個2^n的數~

HashMap在jdk1 8前後的變化

hashmap在jdk1.8之前結構為陣列 鍊錶,缺點就是雜湊函式很難使元素百分百的均勻分布,這會產生一種極端的可能,就是大量的元素存在乙個桶裡,此時的時間複雜度為o n 極大的放慢了計算速率。在jdk1.8之後,hashmap採用陣列加鍊表或是紅黑樹的形式,1 在hashmap新增元素時,按照陣列...

HashMap 底層 原理(JDK 1 8)

原來看過1.7的hashmap底層,1.8更新後也稍微看了一下,沒有進行仔細的總結,今天總結一下1.8底層的原理。本文只討論1.8的底層原理。以下全文為1.8版本的 對於hashmap的資料結構,是老生常談了,面試的時候經常會被問道。底層資料結構為陣列 鍊錶 紅黑樹,儲存的是node節點,紅黑樹是t...

HashMap原始碼分析 JDK1 8

陣列 鍊錶 紅黑樹 陣列儲存元素,當有衝突時,就在該陣列位置形成乙個鍊錶,儲存衝突的元素,當鍊表元素個數大於閾值時,鍊錶就轉換為紅黑樹。transient node table transient int size int threshold final float loadfactor 預設初始容...