HashMap原始碼分析(jdk1 8之前)

2021-08-31 03:42:22 字數 2113 閱讀 6064

hashmap在我們的程式設計中,應用非常廣範。那麼hashmap內部到底是怎麼儲存資料呢,我們先來看看下圖。

hashmap是通過維護陣列和鍊錶的方式,來儲存資料。在上圖中x軸是陣列,每個陣列包含乙個鍊錶,通過hash值在查詢陣列的索引和插入資料。

首先,我們會通過new乙個hashmap的方式建立乙個hashmap物件。這時,會建立hashmpa的資料大小。需要注意的是,我們在查詢資料索引時,是通過按位與的方式,所以陣列的大小為2的n次方。

public hashmap(int initialcapacity, float loadfactor)
在上面的**中,我們通過乙個while迴圈,向左移位capacity變數來確定陣列大小。

陣列建立好後,我們會向hashmap中插入資料。插入資料是根據key的hash值來判斷插入的位置。前面提到過,插入的索引是通過二次hash值對陣列長度求餘得到的。

static int indexfor(int h, int length)
那麼二次hash的過程是什麼呢?我們首先會呼叫key.hashcode方法,將得到的值傳入hash方法中,得到二次hash值。

public int hashcode() 

hash = h;

}return h;

}

在這裡有乙個預設規則選擇31,是因為31是乙個奇素數,它在做乘法的時候可以被移位和減法代替,有更好的效能。

static int hash(int h)
二次hash的原因是因為在做位與操作時,總是從低位計算,陣列長度確定的情況下,高位為0。那麼,在hash值大於陣列長度時,高位不會參與運算,會導致資料堆積在乙個陣列上,降低效能。

解決hash衝突的方法有以下幾種:

1.開發位址法

2.再雜湊發

3.鏈位址法(hashmap採用這種方法)

4.建立公共溢位區

hashmap的put方法

public v put(k key, v value) 

}modcount++;

addentry(hash, key, value, i);

return null;

}

插入資料時,會判斷key是否為空,為空則呼叫putfornullkey方法。在該方法中,獲取第乙個陣列的鍊錶,如果該鍊錶中存在某個結點的key值為null,就替換成新結點,並返回舊結點。否則建立乙個新的結點。

private v putfornullkey(v value) 

}modcount++;

addentry(0, null, value, 0);

return null;

}

當key不為null時,根據key值二次hash計算索引。判斷鍊錶中的結點的hash值和key值是否匹配要插入的資料,如果這兩個值都匹配上,說明該鍊錶中存在該結點,則替換這個結點,並返回舊結點。否則,建立乙個新的結點。

在插入資料後,modcount++,這個屬性是被volatile修飾的,那麼該資料改變時,其他執行緒也會看見。在hashmap的迭代過程中,會先將該值賦值,並在後續操作中,先判斷被賦值的數是否等於modcount,不等於則說明其他執行緒修改了modcount,並丟擲異常。

建立乙個新結點的方法如下

void addentry(int hash, k key, v value, int bucketindex)
hashmap的get方法

public v get(object key) 

return null;

}

這這裡,我們需要提醒的是,hashmap是非安全性的,當多執行緒操作時,可能導致死迴圈。如果乙個執行緒在查詢乙個資料時,另外乙個執行緒刪除了該結點,會導致無法查詢到結點,一直迴圈下去。get方法也是根據二次hash的索引值,匹配hash值和key值是否相等,匹配成功返回value。

分析HashMap 的 JDK 原始碼

緣由 今天好友拿著下面的 問我為什麼 map.entry 這個介面沒有實現 getkey 和 getvalue 方法,卻可以使用,由此,開啟了一番查閱 jdk 原始碼的旅途 map map new hashmap map.put 1,張三 map.put 2,李四 map.put 3,王五 map....

hashmap原始碼分析jdk8

最近看了下jdk8的hashmap原始碼,相比於7,在儲存結構上有了些改變。1.在jdk8之前,hashmap的儲存結構是陣列 鍊錶的形式,那麼這種方式隨著鍊錶的長度增加,效率也凸顯出來。所以在jdk8中這塊做了優化,當鍊表超過一定長度時轉化為紅黑樹來解決這個問題,下面用流程圖畫出hashmap 的...

HashMap原始碼分析 JDK1 8

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