我的個人博客地址:http://swaiter.github.io
HashMap 簡介
HashMap基于哈希表的 Map 接口的實現(xiàn)。此實現(xiàn)提供所有可選的映射操作,并允許使用 null 值和 null 鍵肠虽。(除了不同步和允許使用 null 之外常侣,HashMap 類與 Hashtable 大致相同战惊。)此類不保證映射的順序,特別是它不保證該順序恒久不變冀偶。
值得注意的是HashMap不是線程安全的,如果想要線程安全的HashMap渔嚷,可以通過Collections類的靜態(tài)方法synchronizedMap獲得線程安全的HashMap进鸠。
Map map = Collections.synchronizedMap(new HashMap());
也可以使用ConcurrentHashMap
HashMap的數(shù)據(jù)結(jié)構(gòu)
HashMap的底層主要是基于數(shù)組和鏈表來實現(xiàn)的,它之所以有相當(dāng)快的查詢速度主要是因為它是通過計算散列碼來決定存儲的位置形病。HashMap中主要是通過key的hashCode來計算hash值的客年,只要hashCode相同霞幅,計算出來的hash值就一樣。如果存儲的對象對多了量瓜,就有可能不同的對象所算出來的hash值是相同的司恳,這就出現(xiàn)了所謂的hash沖突。
HashMap屬性
//樹化鏈表節(jié)點的閾值绍傲,當(dāng)某個鏈表的長度大于或者等于這個長度扔傅,則擴(kuò)大數(shù)組容量,或者數(shù)化鏈表
static final int TREEIFY_THRESHOLD = 8;
//初始容量烫饼,必須是2的倍數(shù)猎塞,默認(rèn)是16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
//最大所能容納的key-value 個數(shù)
static final int MAXIMUM_CAPACITY = 1 << 30;
//默認(rèn)的加載因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//存儲數(shù)據(jù)的Node數(shù)組,長度是2的冪杠纵。
transient Node<K,V>[] table;
//keyset 方法要返回的結(jié)果
transient Set<Map.Entry<K,V>> entrySet;
//map中保存的鍵值對的數(shù)量
transient int size;
//hashmap 對象被修改的次數(shù)
transient int modCount;
// 容量乘以裝在因子所得結(jié)果荠耽,如果key-value的 數(shù)量等于該值,則調(diào)用resize方法淡诗,擴(kuò)大容量骇塘,同時修改threshold的值。
int threshold;
//裝載因子
final float loadFactor;
構(gòu)造方法
默認(rèn)構(gòu)造方法將使用默認(rèn)的加載因子(0.75)初始化韩容。
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
put方法
執(zhí)行邏輯:
1)根據(jù)key計算當(dāng)前Node的hash值款违,用于定位對象在HashMap數(shù)組的哪個節(jié)點。
2)判斷table有沒有初始化群凶,如果沒有初始化插爹,則調(diào)用resize()方法為table初始化容量,以及threshold的值请梢。
3)根據(jù)hash值定位該key 對應(yīng)的數(shù)組索引赠尾,如果對應(yīng)的數(shù)組索引位置無值,則調(diào)用newNode()方法毅弧,為該索引創(chuàng)建Node節(jié)點
4)如果根據(jù)hash值定位的數(shù)組索引有Node气嫁,并且Node中的key和需要新增的key相等,則將對應(yīng)的value值更新够坐。
5)如果在已有的table中根據(jù)hash找到Node寸宵,其中Node中的hash值和新增的hash相等,但是key值不相等的元咙,那么創(chuàng)建新的Node梯影,放到當(dāng)前已存在的Node的鏈表尾部。
如果當(dāng)前Node的長度大于8,則調(diào)用treeifyBin()方法擴(kuò)大table數(shù)組的容量庶香,或者將當(dāng)前索引的所有Node節(jié)點變成TreeNode節(jié)點甲棍,變成TreeNode節(jié)點的原因是由于TreeNode節(jié)點組成的鏈表索引元素會快很多。
5)將當(dāng)前的key-value 數(shù)量標(biāo)識size自增赶掖,然后和threshold對比感猛,如果大于threshold的值七扰,則調(diào)用resize()方法,擴(kuò)大當(dāng)前HashMap對象的存儲容量唱遭。
6)返回oldValue或者null
put 方法比較經(jīng)常使用的方法戳寸,主要功能是為HashMap對象添加一個Node 節(jié)點,如果Node存在則更新Node里面的內(nèi)容拷泽。