HashMap原理解析

2021-08-27 23:27:07 字數 3046 閱讀 8192

日常工作中經常用到map,基本上是用map map=new hashmap()來得到乙個hashmap物件,之前並未深入去研究hashmap的實現原理,只是去簡單的去建立然後使用它。

這次想深入了解便,去研究了一下hashmap的原始碼。

做點筆記,記錄一下自己的一些收穫,想到哪寫到哪吧。

hashmap繼承自abstractmap類並實現了map、cloneable、serializable等介面。

hashmap是一種鍊錶雜湊的資料結構。

鍊錶:鍊錶是一種物理儲存單元上非連續、非順序的儲存結構,資料元素的邏輯順序是通過鍊錶中的指標鏈結次序實現的。

雜湊表(hash表):根據關鍵碼(key-value)而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中乙個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做雜湊表。

new乙個hashmap物件時建立了乙個entry table陣列, entry是hashmap的內部類。entry table預設初始化長度為16。

entry table中的某乙個元素及其對應的entry又被稱為桶(bucket)

其結構如下圖所示:

以上是hashmap的內部組織結構圖。

我們主要解釋一下hashmap的put方法:

/**

* 將鍵值對存到hashmap中,如果key在hashmap中已經存在,那麼最終返回被替換掉的value值。

* key 和value允許為空

*/public v put(k key, v value)

}modcount++;

//6不存在,則根據鍵值對建立乙個新的entry物件,然後新增到這個桶的entry鍊錶的頭部。

addentry(hash, key, value, i);

return null;

}/**

* key 為null,則將entry放置到第一桶table[0]中

*/private v putfornullkey(v value)

}modcount++;

addentry(0, null, value, 0);

return null;

}

/**

* 根據特定的hashcode 重新計算hash值,

* 由於jvm生成的的hashcode的低位元組(lower bits)衝突概率大,(jdk只是這麼一說,至於為什麼我也不清楚)

* 為了提高效能,hashmap對key的hashcode再加工,取key的hashcode的高位元組參與運算

*/static int hash(int h)

/*** 返回此hashcode應當分配到的桶的索引

*/static int indexfor(int h, int length)

void resize(int newcapacity) 

entry newtable = new entry[newcapacity];

transfer(newtable);

table = newtable;

threshold = (int)(newcapacity * loadfactor);

}/**

* transfers all entries from current table to newtable.

*/void transfer(entry newtable) while (e != null);}}

}

(1)hashmap允許key為空值,當key為空值時,會把key-value鍵值對放到table[0];

(2)然後計算出key的hash值並得到它的精確索引位址;

(3)根據索引值定位到table中桶(bucket)的位置,遍歷索引處的entry鍊錶,若hash值相同且key相同,則用新的value替換老的value,並返回oldvalue;

(4)若不存在相同key,則呼叫addentry()方法在索引處新增entry物件,並放置在當前位置entry鍊錶的頭部。然後判斷size是否超過了閥值。若超過閥值則呼叫resize(int capacity)方法。

(5)hashmap的put方法裡會呼叫乙個addentry的方法,這可能會導致陣列長度超過閥值(table陣列長度*載入因子),載入因子的經驗值為0.75,為了節省空間我們可以增大載入因子,但時間複雜度會增大。

(6)hashmap的預設初始長度為2的4次方,且每次擴充都是在原有的基礎上乘2,之前一直對為什麼長度要是2的次方迷惑,經過查閱後得到了答案。

put方法裡有乙個indexfor方法會用位運算子(&)比較key的hash值(h)與table的length-1,&比較的是二進位制數(當引數是布林型的時候和邏輯運算子&&有相同的作用只是沒有短路功能),當h=length-1,取length-1,當length為2的n次冪時,length-1的2進製位都為1,與h做與運算,能最大程度利用空間,減少衝突。位運算子(&):當對應位置都為1的時候才為1。

(7)我們盡可能少的增加鍊錶的複雜度,因為時間的複雜度為o(n),而空間的複雜度為o(1),理想的狀態時每個索引的位置之儲存乙個key-value,這樣檢索的效率是最高的,但這樣消耗的空間也是最大的。

(8)因為陣列在記憶體中占用連續儲存的空間,所以擴充的時候得重新定義陣列,並將原entry table打散重新計算hash值後均勻的分布到新的陣列中,這裡要消耗很多的效能,所以我們最好在定義的時候大致確定好陣列的長度。

以上是一些總結,如果想要了解更詳細的,可以看這篇文章

HashMap原理解析

hashmap在jdk1.8之前和jdk1.8之後內部實現有所不同 在jdk1.8之前,hashmap底層是陣列和鍊錶的結構,從jdk1.8開始內部實現使用了陣列和鍊錶以及紅黑樹一 jdk1.8之前的hashmap實現原理 以jdk1.7為例 先看構造方法 public hashmap public...

HashMap的原理解析

進行hashmap原理解析 手寫乙個簡單的hashmap hashmap的底層執行是陣列加鍊表 鍊錶就是為了解決雜湊碰撞的情況 public class hashmap 關羽的hash值是 679082 index is 2 孫權的hash值是 751370 index is 5 張飛的hash值是...

資料結構 HashMap原理解析

hashing 雜湊法或雜湊法 的概念 雜湊法 hashing 是一種將字元組成的字串轉換為固定長度 一般是更短長度 的數值或索引值的方法,稱為雜湊法,也叫雜湊法。由於通過更短的雜湊值比用原始值進行資料庫搜尋更快,這種方法一般用來在資料庫中建立索引並進行搜尋,同時還用在各種解密演算法中。hashma...