HashMap原始碼分析 需要記住的

2021-09-26 09:21:10 字數 2206 閱讀 8022

map介面是另外乙個老祖先

hash表也稱為雜湊表,也有直接譯作雜湊表,hash表是一種根據關鍵字值(key - value)而直接進行訪問的資料結構。也就是說它通過把關鍵碼值對映到表中的乙個位置來訪問記錄,以此來加快查詢的速度。在鍊錶、陣列等資料結構中,查詢某個關鍵字,通常要遍歷整個資料結構,也就是o(n)的時間級,但是對於雜湊表來說,只是o(1)的時間級。

①、為什麼要有雜湊函式?

②、多個 key 通過雜湊函式會得到相同的值,這時候怎麼辦?

對於第乙個問題,雜湊函式的存在能夠幫助我們更快的確定key和value的對映關係,試想一下,如果沒有漢字和拼音的轉換規則(或者漢字和偏旁部首的),給你乙個漢字,你該如何從字典中找到該漢字?我想除了遍歷整部字典,你沒有什麼更好的辦法。

對於第二個問題,多個 key 通過雜湊函式得到相同的值,這其實也是雜湊表最大的問題——衝突。比如同音字漢字,我們得到的拼音就會是相同的,那麼我們該如何在字典中存放同音字漢字呢?有兩種做法:

第一種是開放位址法,當我們遇到衝突了,這時候通過另一種函式再計算一遍,得到相應的對映關係。比如對於漢語字典,乙個字 「餘」,拼音是「yu」,我們將其放在頁碼為567(假設在該位置),這時候又來了乙個漢字「於」,拼音也是「yu」,那麼這時候我們要是按照轉換規則,也得將其放在頁碼為567的位置,但是我們發現這個頁碼已經被占用了,這時候怎麼辦?我們可以在通過另一種函式,得到的值加1。那麼漢字"於"就會被放在576+1=577的位置。

第二種是鏈位址法,我們可以將字典的每一頁都看成是乙個子陣列或者子鍊錶,當遇到衝突了,直接往當前頁碼的子陣列或者子鍊錶裡面填充即可。那麼我們進行同音字查詢的時候,可能需要遍歷其子陣列或者子鍊錶。

對於開放位址法,可能會遇到二次衝突,三次衝突,所以需要良好的雜湊函式,分布的越均勻越好。對於鏈位址法,雖然不會造成二次衝突,但是如果一次衝突很多,那麼會造成子陣列或者子鍊錶很長,那麼我們查詢所需遍歷的時間也會很長。

public class hashmapextends abstractmapimplements map, cloneable, serializable
但是我們發現 hashmap 類即繼承了 abstractmap 介面,也實現了 map 介面,這樣做難道不是多此一舉?後面我們會講的 linkedhashset 集合也有這樣的寫法。

//序列化和反序列化時,通過該欄位進行版本一致性驗證

private static final long serialversionuid = 362498820763181265l;

//預設 hashmap 集合初始容量為16(必須是 2 的倍數)

static final int default_initial_capacity = 1 << 4; // aka 16

//集合的最大容量,如果通過帶參構造指定的最大容量超過此數,預設還是使用此數

static final int maximum_capacity = 1 << 30;

//預設的填充因子

static final float default_load_factor = 0.75f;

//當桶(bucket)上的結點數大於這個值時會轉成紅黑樹(jdk1.8新增)

static final int treeify_threshold = 8;

//當桶(bucket)上的節點數小於這個值時會轉成鍊錶(jdk1.8新增)

static final int untreeify_threshold = 6;

/**(jdk1.8新增)

* 當集合中的容量大於這個值時,表中的桶才能進行樹形化 ,否則桶內元素太多時會擴容,

* 而不是樹形化 為了避免進行擴容、樹形化選擇的衝突,這個值不能小於 4 * treeify_threshold

*/static final int min_treeify_capacity = 64;

注意:後面三個欄位是jdk1.8新增的,主要是用來進行紅黑樹和鍊錶的相互轉換

jdk1.7中如果陣列某個位置發生了hash衝突,使用的是單鏈表的頭插入方法,同一位置的新元素總是放在鍊錶的頭部,這樣與原集合鍊錶對比,擴容之後的可能就是倒序的鍊錶了。

HashMap原始碼分析

public hashmap int initialcapacity,float loadfactor 2 接下來是重要的put方法,put方法用於將鍵值對儲存到map中,讓我們來具體分析一下。public v put k key,v value if key null 若key為null,則將va...

HashMap 原始碼分析

1 getentry object key 方法 final entrygetentry object key return null 根據key的hash值計算出索引,得到table中的位置,然後遍歷table處的鍊錶 for entrye table indexfor hash,table.le...

HashMap原始碼分析

public v put k key,v value if key null return putfornullkey value int hash hash key int i indexfor hash,table.length for entrye table i e null e e.nex...