HashMap原理解析

2021-09-13 19:14:02 字數 3012 閱讀 2578

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

先看構造方法:

public hashmap() 

public hashmap(int initialcapacity, float loadfactor)

在建立乙個空hashmap的時候,會載入預設負載因子 default_load_factor = 0.75f,

預設容量default_initial_capacity = 1 << 4;(2的四次方,16)

負載因子乘以map內部陣列的長度就是map擴容的界限16*0.75=12,所以當內部陣列長度佔滿12就開始擴容,擴容具體邏輯後面再說

下面看看,map如何放入元素:

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.next)

}modcount++;

addentry(hash, key, value, i);

return null;

}

第2-4行:第一次新增元素的時候才真正確定map內部陣列的長度,內部實現邏輯涉及到二進位制移位運算,此處不做詳解

第5-6行新增key為null的元素:

private v putfornullkey(v value) 

}modcount++;

addentry(0, null, value, 0);

return null;

}

迴圈遍歷陣列的0索引位置上的鍊錶,如果發現有元素的key是null,那麼用新值替代舊值.如果發現陣列當前位置沒有元素,那麼直接將key=null的元素新增到當前鍊錶的頭部(頭部插入),新增邏輯如下 addentry(0, null, value, 0);

void addentry(int hash, k key, v value, int bucketindex) 

createentry(hash, key, value, bucketindex);

}

在新增元素的時候:如果發現當前陣列已使用長度超過擴容界限,並且0索引已被使用

那麼兩倍容量地擴容resize(2 * table.length);

void resize(int newcapacity) 

entry newtable = new entry[newcapacity]; // 2倍容量

transfer(newtable, inithashseedasneeded(newcapacity));

table = newtable;

threshold = (int)math.min(newcapacity * loadfactor, maximum_capacity + 1);

}

擴容主要邏輯在第十行: transfer(newtable, inithashseedasneeded(newcapacity));

void transfer(entry newtable, boolean rehash) 

int i = indexfor(e.hash, newcapacity);

e.next = newtable[i]; // 當前節點的的next指向陣列節點

newtable[i] = e; // 當前節點 // 頭部插入

e = next;}}

}

從這裡可以看出,每個鍊錶上的節點移到新的鍊錶上是從頭部插入的,並且從 int i = indexfor(e.hash, newcapacity);可以看出以前在同乙個鍊錶上的節點,在擴容之後不一定在同乙個鍊錶上(newcapacity是原來的2倍)

到此擴容完成,並把舊的陣列遷移到新的陣列上

繼續新增當前的null到新的陣列上

void createentry(int hash, k key, v value, int bucketindex) 

entry(int h, k k, v v, entryn)

從這裡也可以看出是頭插入:新建節點的next指向當前陣列的bucketindex上

從**上看:新增key != null的元素邏輯與上面講的 key = null 一樣

再來看看如何從map中取出元素

public v get(object key)
key = null 和key != null邏輯一樣

此處看看key != null的情況:

entryentry = getentry(key);

final entrygetentry(object key) 

int hash = (key == null) ? 0 : hash(key);

for (entrye = table[indexfor(hash, table.length)];

e != null;

e = e.next)

return null;

}

for迴圈中根據key的hash找到在內部陣列的索引位置,然後遍歷當前索引位置上的鍊錶,一旦找到當前的key,則找到了在鍊錶上的書資料,直接返回,如果沒找到,則響應null

內部資料結構:

HashMap原理解析

日常工作中經常用到map,基本上是用map map new hashmap 來得到乙個hashmap物件,之前並未深入去研究hashmap的實現原理,只是去簡單的去建立然後使用它。這次想深入了解便,去研究了一下hashmap的原始碼。做點筆記,記錄一下自己的一些收穫,想到哪寫到哪吧。hashmap繼...

HashMap的原理解析

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

資料結構 HashMap原理解析

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