深入理解HashMap原始碼
1.HashMap資料結構
首先先看下HashMap的資料結構圖
我們都知道陣列的儲存方式在是連續的,查詢速度比較快,但插入和刪除資料比較慢
而連結串列的儲存方式是非連續的,所以插入和刪除速度較快,但查詢速度就比較慢,HashMap在資料結構上兩種都採用了。
/** * The table, initialized on first use, and resized as * necessary. When allocated, length is always a power of two. * (We also tolerate length zero in some operations to allow * bootstrapping mechanics that are currently not needed.) */ transient Node<K,V>[] table;
再看下Node中的變數 (Node中含有hash值、key、value以及指向下個節點的next)
final int hash; final K key; V value; Node<K,V> next; Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; }
通過這個table變數我們就能理解上面那個資料結構圖,它不僅使用了陣列,而且還採用了連結串列結構。
2.HashMap變數
首先我們看下HashMap中的變數,在看之前思考幾個問題:
1. HashMap資料結構既然使用了陣列,那麼陣列預設記憶體大小是多少?
2.當已使用記憶體大小超過總記憶體的一個百分比後,需要繼續增大記憶體,這個百分比是多少?
3.當連結串列節點長多超過多少時儲存結構變成紅黑樹?
/** * The default initial capacity - MUST be a power of two. */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
由此可以知道陣列的預設大小是16
/**
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30.
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
當陣列不夠大的時候,就會增加記憶體大小,大小的上限為1<<30,也就是2的30次方
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
這個變數就是問題2的答案,也被稱為負載因子,預設為0.75
/**
* The bin count threshold for using a tree rather than list for a
* bin. Bins are converted to trees when adding an element to a
* bin with at least this many nodes. The value must be greater
* than 2 and should be at least 8 to mesh with assumptions in
* tree removal about conversion back to plain bins upon
* shrinkage.
*/
static final int TREEIFY_THRESHOLD = 8;
這個變數就是問題三的答案,當節點數量超過8時,儲存結構轉換成紅黑樹
/**
* The bin count threshold for untreeifying a (split) bin during a
* resize operation. Should be less than TREEIFY_THRESHOLD, and at
* most 6 to mesh with shrinkage detection under removal.
*/
static final int UNTREEIFY_THRESHOLD = 6;
當bin的個數小於6時由樹形結構調整為列表
/**
* The number of key-value mappings contained in this map.
*/
transient int size;
當前HashMap中儲存key-value的大小
/**
* The number of times this HashMap has been structurally modified
* Structural modifications are those that change the number of mappings in
* the HashMap or otherwise modify its internal structure (e.g.,
* rehash). This field is used to make iterators on Collection-views of
* the HashMap fail-fast. (See ConcurrentModificationException).
*/
transient int modCount;
HashMap被修改和刪除的次數
3.HashMap的儲存過程
HashMap hashMap = new HashMap();
hashMap.put("1","1230");
System.out.print(hashMap.get("1"));
我們從hashMap.put()方法開始
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
這裡詳細講下hash()函式,首先先看原始碼:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
如果key的值不為空的話,就把變數h等於key值的hashCode,然後把h的高16位與低16位進行一個異或運算,這樣得到的值和陣列的預設長度16相對應,方便後續計算該Node儲存的陣列下標是多少。
然後回到putVal()方法
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)//初始化tab
n = (tab = resize()).length;//n為陣列總長度
if ((p = tab[i = (n - 1) & hash]) == null)//i為儲存的陣列下標
//傳入的hash值與陣列長度進行位與運算,這樣就可以保證數值不越界,得到結果賦值給i,
//如果i處為空的話,就把node儲存到該下標
tab[i] = newNode(hash, key, value, null);
else {//如果下標i處存有值的話,就使用連結串列結構,此時p=tab[i]
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;//key值存在的話,就不存
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == 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
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
未完。。。。待續
相關推薦
深入理解HashMap原始碼
1.HashMap資料結構 首先先看下HashMap的資料結構圖 我們都知道陣列的儲存方式在是連續的,查詢速度比較快,但插入和刪除資料比較慢 而連結串列的儲存方式是非連續的,所以插入和刪除速度較快,但查詢速度就比較慢,HashMap在資料結構上兩種都採用了。
從原始碼深入理解HashMap(附加HashMap面試題)
HashMap向來是面試中的熱點話題,深入理解了HashMap的底層實現後,才能更好的掌握它,也有利於在專案中更加靈活的使用。 本文基於JDK8進行解析 一、HashMap解析 1. 結構 HashMap結構由陣列加**連結串列(或紅黑樹)**構成。主幹是E
深入理解HashMap(及hash函數的真正巧妙之處)
ssa 什麽 關聯 表示 廣泛 要求 傳遞 所有 總結 原文地址:http://www.iteye.com/topic/539465 Hashmap是一種非常常用的、應用廣泛的數據類型,最近研究到相關的內容,就正好復習一下。網上關於hashmap的文章很多,但到底是自己
深入理解 HashMap
包含 刪除 不同 鍵值 code 1.8 信息 索引 導致 1. 簡介 HashMap 是Java開發中使用頻率最高的鍵值對數據類型容器。它根據鍵的哈希值(hashCode)來存儲數據,訪問速度高,但無法按照順序遍歷。HashMap 允許鍵值為空和記錄為空,非線程安全。 另
深入理解HashMap及面試相關問答
前言 HashMap是面試必備的一個知識點,無論你是初級中級還是高階,基本上逃不過這個問題,下面的內容很簡單,只要你理解了其中的含義,這對你使用hashmap和麵試都是很有幫助的。 正文 首先開啟HashMap,看看中都定義了哪些成員變數。 解釋幾個重點的變數 transi
深入理解hashmap理論篇
之前有過一篇介紹java中hashmap使用的,深入理解hashmap,比較側重於 程式碼分析,沒有從理論上分析hashmap,今天把hashmap的理論部分補充一下(之後應該還有兩篇補充 一篇講紅黑樹一篇講多執行緒)。 雜湊(雜湊)函式到底是幹嘛的?和雜湊表是啥關係?其主要作用和應用場景到底在哪裡? 簡
手把手教你深入理解Spring原始碼-spring開篇(中)
授人以魚不如授人以漁,《手把手教你深入理解Spring原始碼》專欄教你如何學習、思考、閱讀Spring框架,並應對其它開源框架不再畏懼。 接著上篇的文章講,上篇的文章講述了什麼是IOC,這篇講述什麼又是AOP? 一樣的在看這篇文章之前,大家不妨先花點時間思考一下。 1、AOP的設計原理
深入理解hashmap(三)雜湊表和二叉搜尋樹的恩怨情仇
前面兩篇文章介紹了hashmap的原始碼和理論,今天把剩餘的部分紅黑樹講一下。理解好紅黑樹,對我們後續對hashmap或者其他資料結構的理解都是很有好處的。比方說為什麼後面jdk要把hashmap中的單鏈表更新成紅黑樹? 要理解紅黑樹首先要弄清楚普通二叉樹的一些基本概念 父節點和子節點,這個我就不多說了。
深入理解HashMap(原理,查詢,擴容)
面試的時候聞到了Hashmap的擴容機制,之前只看到了Hasmap的實現機制,補一下基礎知識,講的非常好 原文連結: Hashmap是一種非常常用的、應用廣泛的資料型別,最近研究到相關的內容,就正好複習一下。網上關於hashmap的文章很多,但到底是自己學習的總結,就
深入理解HashMap(一次性徹底掌握)
Hashmap是一種非常常用的、應用廣泛的資料型別,最近研究到相關的內容,就正好複習一下。網上關於hashmap的文章很多,但到底是自己學習的總結,就發出來跟大家一起分享,一起討論。 1、hashmap的資料結構 要知道hashmap是什麼,首先要搞清楚它的資料結構,在j
深入扒 HashMap 原始碼
這裡的 jdk 環境是 1.8 會和 1.7 的有區別 一、static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 預設初始化容量,值為 1
深入理解HashMap(及hash函式的真正巧妙之處)
Hashmap是一種非常常用的、應用廣泛的資料型別,最近研究到相關的內容,就正好複習一下。網上關於hashmap的文章很多,但到底是自己學習的總結,就發出來跟大家一起分享,一起討論。 1、hashmap的資料結構 要知道hashmap是什麼,首先要搞清楚它的資料結
深入理解HashMap(精華必看)
3、hashmap的resize 當hashmap中的元素越來越多的時候,碰撞的機率也就越來越高(因為陣列的長度是固定的),所以為了提高查詢的效率,就要對hashmap的陣列進行擴容,陣列擴容這個操作也會出現在ArrayList中,所以這是一個通用的操作,很多人對它的效能表示過懷疑,不過想想我
深入理解HashMap及底層實現
概述:HashMap是我們常用的一種集合類,資料以鍵值對的形式儲存。我們可以在HashMap中儲存指定的key,value鍵值對;也可以根據key值從HashMap中取出相應的value值;也可以通過keySet方法返回key檢視進行迭代。以上是基於HashMap的常見應用,但是光會使用是遠
深入理解HashMap
什麼是HashMap HashMap作為Java語言中一種重要的型別,其儲存資料通過鍵值對的形式儲存,即<key,value>的形式。HashMap繼承AbstractMap類,最終實現的是Map介面。HashMap中資料的Key值不允許重複,Ha
深入理解HashMap原理
3、hashmap的resize 當hashmap中的元素越來越多的時候,碰撞的機率也就越來越高(因為陣列的長度是固定的),所以為了提高查詢的效率,就要對hashmap的陣列進行擴容,陣列擴容這個操作也會出現在ArrayList中,所以這是一個通用的操作,很多人對它的效能表示過懷疑,不過想想我們
深入理解React原始碼
介面更新本質上就是資料的變化。通過把所有會動的東西收斂到狀態(state),React提供了一個非常直觀的前端框架。我也比較喜歡review基於React程式碼,因為我一般都是從資料結構開始看,這樣可以在鑽到細節程式碼之前建立對整個邏輯的初步理解。我也經常會好奇React
深入理解Spring原始碼之自動裝配
自動裝配; Spring利用依賴注入(DI),完成對IOC容器中中各個元件的依賴關係賦值; 1)、@Autowired:自動注入: 1)、預設優先按照型別去容器中找對應的元件:applicationContext.getBean(Bo
HashMap為什麼這麼快? ---深入理解HashMap的雜湊機制
在通過上篇部落格瞭解了 Map 的維持內部的 鍵-值 對的基本方式之後,----不瞭解的看這篇(Java集合的基本概括), 我們便會思考, 在 HashMap 內部是如何組織和排列這些封裝了 鍵-值對的 Map.Entry 實體呢? 如何組織才能達到更高的效率呢? 在瞭解
深入理解OkHttp原始碼(一)——提交請求
本篇文章主要介紹OkHttp執行同步和非同步請求的大體流程。主要流程如下圖: 主要分析到getResponseWidthInterceptorChain方法,該方法為具體的根據請求獲取響應部分,留著後面的部落格再介紹。 Dispatcher類