Java中HashMap底層原理原始碼分析

2021-08-16 11:45:52 字數 2430 閱讀 7959

在介紹hashmap的同時,我會把它和hashtable以及concurrenthashmap的區別也說一下,不過本文主要是介紹hashmap,其實它們的原理差不多,都是陣列加鍊表的形式儲存資料,另外本文所介紹的都是jdk1.8版本的。在介紹之前,先看下map家族的繼承體系圖:

其中,treemap是基於樹實現的,其他三個都是雜湊表結構。

hashmap和hashtable的主要區別是

1. hashtable是執行緒安全,而hashmap則非執行緒安全,hashtable的實現方法裡面大部分都新增了synchronized關鍵字來確保執行緒同步,因此相對而言hashmap效能會高一些,在多執行緒環境下若使用hashmap需要使用collections.synchronizedmap()方法來獲取乙個執行緒安全的集合。

2. hashmap的鍵和值都可以為null,而hashtable的鍵值都不能為null。

3. hashmap的初始容量為16,hashtable初始容量為11,兩者的填充因子預設都是0.75。hashmap擴充套件容量是當前容量翻倍即:capacity*2,hashtable擴充套件容量是容量翻倍+1即:capacity*2+1(關於擴容和填充因子後面會講)

4. 兩者的雜湊演算法不同,hashmap是先對key(鍵)求hashcode碼,然後再把這個碼值得高位和低位做異或運算,原始碼如下:

static final int hash(object key)
i = (n - 1) & hash
然後把hash(key)返回的雜湊值與hashmap的初始容量(也叫初始陣列的長度)減一做&(與運算)就可以計算出此鍵值對應該儲存到陣列的那個位置上(hash&(n-1))。這裡為什麼不用key本身的hashcode方法,而又是右移動16位又是異或操作。開發人員這樣做的目的是什麼呢?我的理解是當陣列容量很小的時候,計算元素在陣列中的位置(n-1)&hash,只用到了hash值的低位,這樣當不同的hash值低位相同,高位不同的時候會產生衝突。實際上的hash值將hashcode低16位與高16位做異或運算,相當於混合了高位和低位,增加了隨機性。當然是衝突越少越好,元素的分布越隨機越好。

而hashtable計算位置的方式如下:

int hash = key.hashcode();

int index = (hash & 0x7fffffff) % tab.length;

直接計算key的雜湊碼,然後與2的31次方做&(與運算),然後對陣列長度取餘數計算位置。

hashmap訪問元素詳解

hashmap的儲存方式是雜湊表,那麼什麼是雜湊表,其實就是陣列+鍊錶。hashmap初始陣列長度為16。陣列的每個元素都儲存著煉表頭的位址(或者為null),在向hashmap中put(key,value)的時候,先使用hash演算法計算雜湊值,然後再和陣列的長度減一做與運算。計算出此鍵值對應該儲存到陣列的那個位置上,如果此位置沒有元素,意思就是鍊錶的頭結點為null,那麼就新建乙個node結點,把key,value以及next儲存。node類原始碼如下:

static class nodeimplements map.entry

....

......

........

}

static final int default_initial_capacity = 1 << 4; // 預設初始陣列容量 16

static final int maximum_capacity = 1 << 30; //最大容量

static final float default_load_factor = 0.75f; //裝載因子預設0.75

static final int treeify_threshold = 8; //單鏈表結點個數超過8就轉成紅黑樹

int threshold; //閾值,超過此數,就進行擴充套件容量

下面看下hashmap儲存元素的大致情況:

現在看下put操作的原始碼解析:

現在看下get操作的原始碼解析:

Java中HashMap底層原理原始碼分析

在介紹hashmap的同時,我會把它和hashtable以及concurrenthashmap的區別也說一下,不過本文主要是介紹hashmap,其實它們的原理差不多,都是陣列加鍊表的形式儲存資料,另外本文所介紹的都是jdk1.8版本的。在介紹之前,先看下map家族的繼承體系圖 其中,treemap是...

HashMap底層原理

1.hashmap概述 hashmap是基於雜湊表的map介面的非同步實現。此實現提供所有可選的對映操作,並允許使用null值和null鍵。此類不保證對映的順序,特別是它不保證該順序恆久不變。2.hashmap的資料結構 注意,迭代器的快速失敗行為不能得到保證,一般來說,存在非同步的併發修改時,不可...

HashMap 底層分析

更多 hashmap 與 concurrenthashmap 相關請檢視這裡。以下基於 jdk1.7 分析。如圖所示,hashmap 底層是基於陣列和鍊錶實現的。其中有兩個重要的引數 容量的預設大小是 16,負載因子是 0.75,當hashmap的size 16 0.75時就會發生擴容 容量和負載因...