HashMap原始碼分析

2022-05-25 15:24:11 字數 3845 閱讀 4801

hashmap是乙個底層用陣列+鍊錶實現的儲存kv鍵值對資料結構,它允許null鍵和null值。

hashmap的儲存規則是,根據k的hashcode運算得到hash值,然後根據hash值運算得到下標,如果陣列中該下標沒有值就放入,有值就乙個乙個比較是否hash值相同並且equals也為true,如果是就用value更新原來的value,如果到達最後都沒找到相同的,就新增節點,在jdk1.8中進行了優化,當鍊表長度達到8時,就把鍊錶變為紅黑樹

public class hashmapextends abstractmapimplements map, cloneable, serializable
hashmap繼承了abstractmap並重寫了裡面的方法。

hashmap實現了cloneable介面,可以被轉殖。

hashmap實現了serializable介面,可以被序列化。

//預設初始化容量16

static final int default_initial_capacity = 1 << 4;

//最大容量為2的30此方法

static final int maximum_capacity = 1 << 30;

//預設載入因子0.75

static final float default_load_factor = 0.75f;

//鍊錶轉成樹的閾值

static final int treeify_threshold = 8;

//樹轉換成鍊錶的閾值

static final int untreeify_threshold = 6;

//轉換成樹的最小容量閾值

static final int min_treeify_capacity = 64;

//儲存節點的陣列

transient node table;

//儲存的所有節點

transient set> entryset;

//儲存節點個數

transient int size;

//修改次數,用於迭代器的快速失敗

transient int modcount;

//擴容的閾值

int threshold;

//載入因子

final float loadfactor;

static class nodeimplements map.entry

public final k getkey()

public final v getvalue()

public final string tostring()

public final int hashcode()

public final v setvalue(v newvalue)

public final boolean equals(object o)

return false;}}

//指定初始化容量和增長因子的構造器

public hashmap(int initialcapacity, float loadfactor)

//通過一定的演算法得到2的n次方近似於這個數

static final int tablesizefor(int cap)

//指定初始化大小的構造器

public hashmap(int initialcapacity)

//無參構造器

public hashmap()

//使用map初始化構造器

public hashmap(map extends k, ? extends v> m)

put(k,v)新增kv鍵值對

public v put(k key, v value) 

static final int hash(object key)

final v putval(int hash, k key, v value, boolean onlyifabsent,

boolean evict)

if (e.hash == hash &&

((k = e.key) == key || (key != null && key.equals(k))))

break;

p = e;}}

v oldvalue = e.value;

if (!onlyifabsent || oldvalue == null)

e.value = value;

afternodeaccess(e);

//如果是替換舊值,並沒有修改modcount

return oldvalue;}}

++modcount;

if (++size > threshold)

//新增了元素大於閾值,進行擴容

resize();

afternodeinsertion(evict);

return null;

}//初始化或對陣列進行二倍擴容

final node resize()

else if ((newcap = oldcap << 1) < maximum_capacity &&

oldcap >= default_initial_capacity)//原容量擴大二倍小於最大容量 並且 原容量要大於等於預設的初始化容量

newthr = oldthr << 1; // double threshold

}else if (oldthr > 0) //用原來的閾值初始化陣列大小(構造的時候如果指定了初始化大小是使用threshold來儲存的)

newcap = oldthr;

else

if (newthr == 0)

threshold = newthr;

@suppresswarnings()

//建立乙個新容量大小的節點陣列

node newtab = (node)new node[newcap];

table = newtab;

if (oldtab != null)

else

} while ((e = next) != null);

if (lotail != null)

if (hitail != null) }}

}}return newtab;

}

public v remove(object key) 

final noderemovenode(int hash, object key, object value,

boolean matchvalue, boolean movable)

p = e;

} while ((e = e.next) != null);}}

if (node != null && (!matchvalue || (v = node.value) == value ||

(value != null && value.equals(v))))

}return null;

}

但是hashmap為什麼要有modcount這個屬性呢?既然不是執行緒安全的,那麼快速失敗的意義在哪兒呢?而且如果put方法是key已存在,只是將新值替換舊值,modcount並沒有改變,難道你在使用迭代器遍歷時,其他執行緒修改了值,不用快速失敗嗎?

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