數據結構是java學習中很重要的一部分,HashMap也是數據結構中很常用的一部分。我們將通過源碼對HashMap的方法和結構進行分析和理解。
爲了能讓我的理解和源碼能更明白清晰的呈現出來,我將使用代碼和解析一起的方式展示給大家。另外,這只是我個人的理解和分析,大家可以先看一下再去找更清晰準確的文章進行深入理解。我看到一篇不錯的文章就鏈接給大家吧。我目前僅僅分析了基本的put()方法的源碼,至於紅黑樹,鏈表之後再給大家詳細分析。
轉自zju_jzb的博客
//HashMap的put方法源代碼以及個人理解解析
/*
* 基本思想:
* 在hashmap中底層是數組+鏈表式存儲
* 先是按照key值進行hash作爲存儲地址在結構中進行尋找
* 找到後先看該地址是否爲空,如果爲空則直接存儲就可以
* 如果不爲空,就表示該地址已經存儲元素,就需要進行覆蓋
*
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict)
{
Node<K,V>[] tab; Node<K,V> p; int n, i;
/*
* 定義變量,tab表示節點數組,是哈希桶數組(可以用來存儲hashmap
* 對應的key,value對節點元素)
* p表示節點;n表示數組長度;i表示數組下標;
*/
if ((tab = table) == null || (n = tab.length) == 0)
/*
* table實際上也代表節點數組
* 該語句判斷數組是否爲空,或者長度爲0
*/
n = (tab = resize()).length;
//如果是那麼重新定義數組的長度,resize表示重新定義長度
if ((p = tab[i = (n - 1) & hash]) == null)
/*
* 該語句使用i = (n - 1) & hash的位運算方式來確定數組下標,
* 將這個下標位置的節點元素賦值給p,判斷p是否爲空
* (實際也就是判斷要插入的元素hash後的地址是否已存在元素)
*/
tab[i] = newNode(hash, key, value, null);
//如果爲空表示該地址沒有存儲元素,可以直接創建一個新的節點元素進行存儲
else {
/*否則表示該地址已經存在元素,
* 以及當兩者key值相等時執行覆蓋操作
*/
Node<K,V> e; K k;
/*
* 定義變量,e表示節點元素,k從下面k = p.key語句可以看出表示p的key值
*/
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
/*
* 判斷hash值是否相同,並且同時判斷key是否equals
*/
e = p;
//如果滿足那麼先將p節點元素賦值給e,
//因爲後面可能還會對相同key值的節點進行操作,
//我們放到最後再進行覆蓋或者鏈表,紅黑樹插入
***//下面是紅黑樹節點***
else if (p instanceof TreeNode)
/*
* 判斷p的是否是TreeNode類型的節點對象
*/
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
/*
* 如果是
*/
***//下面是鏈表節點***
else {
for (int binCount = 0; ; ++binCount) {
/*
* binCount充當計數器
*/
if ((e = p.next) == null) {
/*
* 判斷如果p的下一個元素是null,表示已經到頭了
*/
p.next = newNode(hash, key, value, null);
//直接在鏈表結尾增加新元素
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
/*
* 判斷計數值是否還
*/
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
/*
* 如果key值相同。接下來就要進行覆蓋
* 在e節點不爲空的前提下進行下列操作
*/
V oldValue = e.value;
//變量創建及賦值,將e節點的value值賦值給變量oldValue
if (!onlyIfAbsent || oldValue == null)
/*
* 判斷是否進行覆蓋操作,
* onlyIfAbsent實際上就是控制是否進行覆蓋操作,
* 如果爲true不進行覆蓋,false進行覆蓋
* 當onlyIfAbsent爲false或者oldValue爲null時進行下面操作
*/
e.value = value;
//進行覆蓋操作
afterNodeAccess(e);
//空函數
return oldValue;
//返回oldValue
}
}
++modCount;
if (++size > threshold)
/*
* 判斷是否還能裝的下,是否應該擴容
*/
resize();
/*
* 如果是,那麼進行擴容
*/
afterNodeInsertion(evict);
return null;
//返回空值。
}