1、前言node
本文由jdk1.8源碼整理而得,附自制jdk1.8底層數據結構圖,並截取部分源碼加以說明結構關係。算法
2、jdk1.8 HashMap底層數據結構圖數據結構
3、源碼spa
1.散列表(Hash table,也叫哈希表):code
/** * 表,第一次使用時初始化(而非實例化集合時進行初始化),並根據須要調整大小。當分配時,長度老是2的冪。(在某些操做中,咱們還容許長度爲零,以容許當前不須要的引導機制。)
*/ transient Node<K,V>[] table;
2.鏈表:blog
/** * Basic hash bin node, used for most entries. (See below for * TreeNode subclass, and in LinkedHashMap for its Entry subclass.) */ static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next;
…… }
3.紅黑樹:源碼
/** * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn * extends Node) so can be used as extension of either regular or * linked node. */ static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> { TreeNode<K,V> parent; // red-black tree links TreeNode<K,V> left; TreeNode<K,V> right; TreeNode<K,V> prev; // needed to unlink next upon deletion boolean red; …… }
4、問題探究hash
1.散列表後面跟的「鏈表、紅黑樹」是怎麼來的,都解決了哪些問題?it
答:io
①鏈表的由來:Hash碰撞:不一樣的元素經過hash算法可能會獲得相同的hash值,若是都放同一個桶裏,後面放進去的就會覆蓋前面放的,因此爲了解決hash碰撞時元素被覆蓋的問題,就有了在桶裏放鏈表。
②紅黑樹的由來:假設如今HashMap集合中大多數的元素都放到了同一個桶裏(由hash值計算而得的桶的位置相同),那麼這些元素就在這個桶後面連成了鏈表。如今須要查詢某個元素,那麼此時的查詢效率就很慢了,它是在作鏈表查詢( O(N) 的查詢效率)。爲了解決這個問題,就引入了紅黑樹( log(n) 的查詢效率):當鏈表到達必定長度時就在鏈表的後面建立紅黑樹。
③其實,「儘可能避免hash 衝突,讓元素較爲均勻的放置到每一個桶」纔是查詢效率最高的( O(1) 的查詢效率),這和hash算法的實現息息相關,這裏不作深究。
2.如圖可知,散列表後面跟的數據結構有多是鏈表,也有多是紅黑樹。散列表後面跟什麼數據結構是怎麼肯定的?
答:
①鏈表節點轉換成紅黑樹節點的閾值, 節點數 >= 8 就轉:
static final int TREEIFY_THRESHOLD = 8;
②紅黑樹節點轉換鏈表節點的閾值, 節點數 <= 6 就轉:
static final int UNTREEIFY_THRESHOLD = 6;
③轉紅黑樹時, table的最小長度:
static final int MIN_TREEIFY_CAPACITY = 64;