1. 程式人生 > 其它 >HashMap的put和get方法原理

HashMap的put和get方法原理

JAVA中的陣列,在新增或者刪除元素的時候,都會複製一個新陣列,比較耗記憶體。但是陣列的遍歷則是非常高效的。連結串列則是相反,遍歷慢(需要遍歷陣列,一直找到值相等的元素才算找到),而新增和刪除元素代價低。

有沒有辦法結合兩者的特點,做到尋找元素快,插入元素或者刪除元素代價低呢?答案是利用哈利表。

HashMap put操作

這裡寫圖片描述

當使用HashMap的put方法的時候,有兩個問題要解決:

1、長度為16的陣列中,元素儲存在哪個位置
2、如果key出現hash衝突,如何解決

第一個問題,HashMap 是使用下面的演算法來計算元素的存放位置的。

int hash = hash(key);
int i = indexFor(hash, table.length);

1
2

首先先hash,之後結合陣列的長度進行一個&操作得到得到陣列的下標。

第二個問題 則利用Entry類的next變數來實現連結串列,把最新的元素放到連結串列頭,舊的資料則被最新的元素的next變數引用著。
舉個例子,假設元素Entry<"1","1">通過hash演算法算出存到下標為0的位置上,後面又新增一個Entry<"2","2">,
假設Entry<"2","2">通過hash演算法算出也需要存到下標為0的陣列中,那麼此時連結串列是下面這個樣子的:

Entry<”2”,”2”> –> Entry<”1”,”1”>

也即是說,當key出現hash衝突的時候,連結串列中的第一個元素都是後面最新新增進來的那個,之前的則被next變數引用著。雖然這裡是插入的動作,但是由於使用了連結串列,所以無需像陣列的插入那樣,進行陣列拷貝。

HashMap get操作

這個操作的原理就比較簡單,只需要根據key的hashcode算出元素在陣列中的下標,之後遍歷Entry物件連結串列,直到找到元素為止。


int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, table.length)];e != null;e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}



這裡有兩個注意點:
1、這裡利用key的hashcode方法和equals方法,所以在使用HashMap的時候,如果使用物件作為key,最好覆寫key的hashcode和equals方法
不然可能出put到HashMap的時候,成功了,但是get的時候卻沒有找到資料
2、如果key hash衝突太多,會造成連結串列過長,在連結串列中查詢元素的時候,會比較慢

hash衝突後優化方案

如果出現了大量hash衝突,那麼遍歷連結串列的時候,會比較慢。JDK 1.8裡面,當連結串列的長度大於閥值(預設為8)的時候,會使用紅黑樹來儲存資料,以便加快key的查詢速度。

總結

HashMap使用了陣列+連結串列的方案,做到了讀取快,插入快的目的,但是HashMap還是一些使用上的問題的:
1、執行緒不安全
2、當容量不夠時,會進行rehash的流程,非常耗資源
————————————————
版權宣告:本文為CSDN博主「Sam_Deep_Thinking」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/linsongbin1/article/details/54667453