概述
HashMap 是我們常用的集合之一,其資料是鍵值對的格式儲存的,底層使用的連結串列陣列實現的,當某個連結串列的長度達到一定長度時,會優先對陣列連結串列進行擴容,當連結串列陣列達到一定的長度後,便會將連結串列轉換為紅黑樹。我們常使用的方法有的 put、get、containsKey、containsValue 等,接下來我們會通過原始碼解析來了解他是如何實現的。但凡有理解偏差,也希望各位不要吝嗇,盡情指出,共同成長~
相關名詞
capacity
連結串列陣列長度,預設值 16,且值必須為 2 的冪次方,可以在建立 HashMap 時進行設定,如果建立 HashMap 時設定的不是 2 的冪次方,便會將陣列長度設定為大於該值的 2 的冪次方。
loadFactor
負載係數,通過該值來計算出擴容閾值(threshold)。
threshold
擴容閾值,當 map 的大小(鍵值對的對映數量)大於等於該值的時候,便會對連結串列陣列進行擴容,具體計算公式為 capacity * loadFactor = threshold
原始碼解析
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
/**
* 連結串列陣列預設初始化長度
*/
static final int DEFAULT_INITIAL_CAPACITY = 16;
/**
* 連結串列陣列的最大長度,達到該長度後,連結串列陣列將不再進行擴容
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* 負載係數預設值
*/
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;
/**
* HashMap 儲存資料使用的連結串列類
*/
static class Node<K,V> implements Map.Entry<K,V> {
/**
* key 的 hash 值
*/
final int hash;
/**
* map 的 key
*/
final K key;
/**
* map 的 value
*/
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;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
/**
* 獲取 key 的雜湊值,具體邏輯如下
* 如果 key 為空,返回 0
* 如果 key 不為空, key 的 hascode 記為 a,a 無符號位移 16 位記為 b,
* 然後返回 a 跟 b 位異運算的值。
* Java 各種位運算解析參考 https://blog.zhangyong.io/java-bit-operations/
*/
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
/**
* 如果 x 實現了 Comparable 介面,則返回 x 的真實型別
* 否則返回 null
*/
static Class<?> comparableClassFor(Object x) {
if (x instanceof Comparable) {
Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
if ((c = x.getClass()) == String.class) // bypass checks
return c;
if ((ts = c.getGenericInterfaces()) != null) {
for (int i = 0; i < ts.length; ++i) {
if (((t = ts[i]) instanceof ParameterizedType) &&
((p = (ParameterizedType)t).getRawType() ==
Comparable.class) &&
(as = p.getActualTypeArguments()) != null &&
as.length == 1 && as[0] == c) // type arg is c
return c;
}
}
}
return null;
}
/**
* 如果 x 跟 x 都實現了 Comparable 且型別相同,則呼叫 compareTo 比較大小並返回結果,
* 否則返回 0
*/
@SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
static int compareComparables(Class<?> kc, Object k, Object x) {
return (x == null || x.getClass() != kc ? 0 :
((Comparable)k).compareTo(x));
}
/**
* 根據陣列長度計算擴容閾值
*/
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
/**
* 存放資料的連結串列陣列,本篇文章中所說的陣列基本都是連結串列陣列
*/
transient Node<K,V>[] table;
/**
* 鍵值對對映個數,map 容量
*/
transient int size;
/**
* 內部結構被改變的次數,例如 修改了鍵值對的對映個數或者以其他方式修改了內部結構,
* 例如重新hash,該欄位主要用於在進行遍歷時快速失敗。(渣渣翻譯,可否準確........)
*/
transient int modCount;
/**
* 擴容閾值,當 map 的大小超過該值,便會對陣列進行擴容
*/
int threshold;
/**
* 負載係數,連結串列陣列長度 * 負載係數 = 擴容閾值
*/
final float loadFactor;
/**
* 構造方法,指定連結串列陣列長度和負載係數,構造方法中沒有直接初始化連結串列陣列,
* 而是通過 capacity 計算出了擴容閾值,然後在第一次 put 資料的時候,進行
* 初始化連結串列陣列長度,而長度直接等於擴容閾值。該建構函式只做了兩件事:
* 1. 設定負載係數。
* 2. 根據是初始化的長度設定擴容閾值,擴容閾值始終是 大於等於 capacity 的
* 2 的冪次方
*
*/
public HashMap(int initialCapacity, float loadFactor) {
// 引數校驗
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
// 設定負載係數
this.loadFactor = loadFactor;
// 計算擴容閾值
this.threshold = tableSizeFor(initialCapacity);
}
/**
* 構造方法,指定連結串列陣列長度
*/
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
/**
* 預設構造方法,所有成員變數均為預設值
*/
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
}
/**
* 構造方法,傳入一個另一個 Map,將資料匯入到新生成的 Map 中
*/
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
// 呼叫 putall 的實現方法
putMapEntries(m, false);
}
/**
* putall 的實現方法
*/
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
// 引數 map 的長度賦值給臨時變數 s
int s = m.size();
// 判斷是否是一個空 map
if (s > 0) {
// 如果是一個空 map,則計算出這個新 map 的擴容閾值,然後在第一次 put 資料
// 的時候初始化連結串列陣列,長度便是這個擴容閾值,這裡初始化 map 的邏輯是跟調
// 用指定 capacity 的構造方法的邏輯是一致的。
if (table == null) {
// 計算出新 map 的擴容閾值(也就是連結串列陣列的長度)
float ft = ((float)s / loadFactor) + 1.0F;
// 限定最大不能超過長度閾值
int t = ((ft < (float)MAXIMUM_CAPACITY) ?
(int)ft : MAXIMUM_CAPACITY);
// 如果新的擴容閾值大於當前擴容閾值,才會將當前擴容閾值設定為新的擴容閾值,
// 防止連結串列陣列長度縮短
if (t > threshold)
// 得出正確的擴容閾值(連結串列陣列長度),必須為 2 的冪次方
threshold = tableSizeFor(t);
} else if (s > threshold) {
// 如果不為空,且引數 map 的大小超過了擴容閾值,那麼也進行擴容。
resize();
}
// 迴圈呼叫 putVal 方法插入資料
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
K key = e.getKey();
V value = e.getValue();
putVal(hash(key), key, value, false, evict);
}
}
}
/**
* 獲取鍵值對對映個數
*/
public int size() {
return size;
}
/**
* 判斷 map 是否為空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 通過 key 獲取值
*/
public V get(Object key) {
Node<K,V> e;
// 將 key 進行 hash,然後通過 key 的 hash 值跟 key 獲取連結串列節點,
// 然後返回連結串列節點中儲存 value
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
/**
* 通過 key 的 hash 值跟 key 獲取連結串列節點
* @param hash key 的 hah 值
* @param key key
* @return key 對應的連結串列節點
*/
final Node<K,V> getNode(int hash, Object key) {
// 當前連結串列陣列
Node<K,V>[] tab;
// key 所在陣列位置中對應的連結串列頭部
Node<K,V> first,
// 迴圈遍歷連結串列時用到的臨時變數
Node<K,v> e;
// 當前連結串列陣列的長度
int n;
// 臨時變數 key
K k;
// 將當前連結串列陣列及其長度賦值給臨時變數,並檢驗陣列不為空,以及所在陣列位置的連結串列不為空
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
// 校驗是是否是連結串列的頭部,如果是進行查詢的 key,則直接返回,否則進行連結串列遍歷
if (first.hash == hash &&
((k = first.key) == key || (key != null && key.equals(k)))) {
return first;
}
// 賦值連結串列的下一個節點給臨時變數,並校驗連結串列的下一個不為空,
// 如果為空則表示不存在該 key 不存在,直接返回 null
if ((e = first.next) != null) {
// 如果是紅黑樹,則遍歷紅黑樹
if (first instanceof TreeNode) {
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
}
// 迴圈遍歷整個連結串列
do {
// 如果 hash 相等且 key 相等,則返回該節點
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
/**
* 判斷 key 是否存在
*/
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
/**
* 插入資料
*
* @param key 被插入資料的 key
* @param value 被插入資料的值
* @return 如果key存在返回key對應的舊值,否則返回 null
*/
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
/**
* 插入資料實現
*
* @param hash key 的 hash 值
* @param key
* @param value alue
* @param onlyIfAbsent 如果為 true,不替換已存在的值
* @param evict 如果為 false,代表 連結串列陣列 處於建立模式
* @return 如果 key 存在,返回舊值,否則返回空
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
// 當前的連結串列陣列備份
Node<K,V>[] tab;
// 臨時變數,連結串列陣列下標對應的連結串列的第一個元素
Node<K,V> p;
// 當前連結串列陣列的長度
int n,
// 資料在連結串列陣列中所處的位置,即下標
int i;
// 如果是第一次執行,初始化連結串列陣列的長度
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
// 根據 key 的 hash 值和陣列長度計算資料所處陣列中的位置,如果該下標下的連結串列為空,
// 直接賦值
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
// 如果 key 已存在對應的連結串列節點
Node<K,V> e;
K k;
// 如果插入的資料的 key 的 hash 值與存放位置的連結串列的頭元素的 hash 值相同,
// 且 key 相等,則賦值給 變數 e
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k)))) {
e = p;
} else if (p instanceof TreeNode) {
// 如果是紅黑樹,則呼叫紅黑樹的節點的賦值方法進行賦值,如果 key 已存在,
// 返回已存在的樹節點
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
} else {
// 否則遍歷連結串列
for (int binCount = 0; ; ++binCount) {
// 首先賦值臨時變數 e 為連結串列節點的下一個元素,然後判斷如果遍歷到連結串列底部
// (連結串列的下一個元素為空),則進行賦值,然後跳出迴圈
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
// 如果連結串列長度到達 7 個,將連結串列轉換為紅黑樹,
if (binCount >= TREEIFY_THRESHOLD - 1) {
treeifyBin(tab, hash);
}
break;
}
// 如果 key 已經存在,將已存在的 key 對應 的節點賦值給臨時變數 e,
// 然後跳出迴圈
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))){
break;
}
// 更新變數 p 為 p 的下個節點
p = e;
}
}
// 如果臨時 e 不為空,表示 key 已經存在
if (e != null) {
// 備份 key 對應的舊值
V oldValue = e.value;
// 如果 onlyIfAbsent 為 false 或者舊值為空,則替換為新值
if (!onlyIfAbsent || oldValue == null) {
e.value = value;
}
// HashMap 的該方法為空方法,沒有實現,LinkedHashMap 中進行了實現
afterNodeAccess(e);
// 返回舊值
return oldValue;
}
}
// 記錄修改次數的變數加1
++modCount;
// 容量加1,如果超過擴容閾值,進行擴容
if (++size > threshold) {
resize();
}
// HashMap 的該方法為空方法,沒有實現,LinkedHashMap 中進行了實現
afterNodeInsertion(evict);
return null;
}
/**
* 重新設定連結串列陣列的長度
*
* @return 新長度的連結串列陣列
*/
final Node<K,V>[] resize() {
// 將連結串列陣列,陣列長度,擴容閾值賦值給臨時變數進行備份
Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
// 將擴容閾值賦值給臨時變數
int oldThr = threshold;
// 宣告新的長度跟擴容閾值對應的臨時變數
int newCap, newThr = 0;
// 判斷 map 中是否已經存在資料,如果存在資料,則陣列長度大於0
if (oldCap > 0) {
// 如果長度達到設定的最大長度閾值閾值,則將擴容閾值設定為 Integer 的最大值。
// 代表將不再會對陣列進行擴容,返回原陣列。
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
// 設定新的長度,然後判斷新的長度如果小於最大容量閾值並且當前長度小於預設長度,
// 便設定新的擴容閾值,其新值都是舊值的兩倍
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY) {
newThr = oldThr << 1;
}
}
// 如果長度為0且擴容閾值大於0,直接將容量設定為擴容閾值
else if (oldThr > 0)
newCap = oldThr;
// 如果都為0,則設定為預設值
else {
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
// 如果擴容閾值還沒有進行初始化,初始化擴容閾值
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
// 判斷如果新的陣列長度大於擴容上限閾值,則直接設定為 Integer 最大值,
// 代表不再進行擴容,否則設定為已經計算出來的擴容閾值
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
}
// 賦值給成員變數擴容閾值
threshold = newThr;
// 建立一個新長度的陣列
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
// 賦值給連結串列陣列
table = newTab;
// 如果老的連結串列陣列資料不為空,則進行遷資料移
if (oldTab != null) {
// 迴圈遍歷就的連結串列陣列
for (int j = 0; j < oldCap; ++j) {
// 臨時變數
Node<K,V> e;
// 賦值給臨時變數並判斷該陣列下標下的連結串列不為空
if ((e = oldTab[j]) != null) {
// 刪除該位置對於連結串列的引用,使其可以進行垃圾回收?
// 自己的理解,不確定是否正確。。。。。
oldTab[j] = null;
// 如果該位置下的連結串列長度為一,則直接重新結算改節點在新陣列中的
// 位置,並新增到新的陣列中。Q:直接設定到該位置的頭部節點?
// 如何確定該位置沒有資料呢?
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
else if (e instanceof TreeNode)
// 如果是紅黑樹,則將該節點下的子節點分散到新的陣列中去
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else {
// 連結串列優化重hash的程式碼塊
// 宣告臨時變數
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
// 節點的下一個變數賦值給臨時變數
next = e.next;
// 原索引
if ((e.hash & oldCap) == 0) {
// 第一次進來,設定頭節點,否則設定尾節點
if (loTail == null) {
loHead = e;
} else {
loTail.next = e;
}
// 無論如何,都更新尾節點
loTail = e;
} else {
// 原索引+oldCap
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
// 存放在原索引位置
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
// 存放在原索引+oldCap的位置裡
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}
/**
* 嘗試將連結串列陣列轉換為紅黑樹
* @param tab 連結串列陣列
* @param hash 插入 key 的 hash 值
*/
final void treeifyBin(Node<K,V>[] tab, int hash) {
// 宣告臨時變數
int n, index; Node<K,V> e;
// 如果連結串列陣列為空或者連結串列陣列的長度小於閾值時,優先進行擴容
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) {
resize();
}
// 計算 key 在連結串列陣列中的具體下標,並校驗該位置下的連結串列不為空
else if ((e = tab[index = (n - 1) & hash]) != null) {
// 宣告臨時變數
TreeNode<K,V> hd = null, tl = null;
// 遍歷整個連結串列,並設定紅黑樹的 pre next 相關節點
do {
// 將連結串列節點替換為紅黑樹節點
TreeNode<K,V> p = replacementTreeNode(e, null);
// 設定 pre next 相關節點
if (tl == null) {
hd = p;
} else {
p.prev = tl;
tl.next = p;
}
tl = p;
} while ((e = e.next) != null);
// 把連結串列所處在陣列的位置重新複製給新的紅黑樹 root 節點,
// 並判斷 root 節點不為空,然後將連結串列轉換為紅黑樹。
if ((tab[index] = hd) != null)
hd.treeify(tab);
}
}
/**
* 將另一個 map 中的資料插入到當前 map 中
*
* @param m 另一個儲存資料的 map
* @throws NullPointerException 如果引數 map 為空
*/
public void putAll(Map<? extends K, ? extends V> m) {
// 呼叫實現方法
putMapEntries(m, true);
}
/**
* 移除指定 key 的鍵值對對映
*
* @param key 即將被移除的 key
* @return 如果 key 存在則返回 key 對應的 value,否則返回 null
*/
public V remove(Object key) {
// 被移除的節點
Node<K,V> e;
// 移除節點並返回節點的 value
return (e = removeNode(hash(key), key, null, false, true)) == null ?
null : e.value;
}
/**
* Map.remove 的實現方法
*
* @param hash key 的 hash 值
* @param key 即將被移除的 key
* @param value 如果 matchValue 為 true,則當 key 與 value 同時一致時才移除
* @param matchValue 如果為 true 則校驗 key 對應的 value 與傳入的是否一致
* @param movable 如果為 false 則不一定其他節點
* @return 如果 key 存在則返回被移除的節點,否則返回 null
*/
final Node<K,V> removeNode(int hash, Object key, Object value,
boolean matchValue, boolean movable) {
//宣告臨時變數
Node<K,V>[] tab; Node<K,V> p; int n, index;
// 如果當前連結串列陣列不為空且 key 所在的陣列下標對應的連結串列不為空
if ((tab = table) != null && (n = tab.length) > 0 &&
(p = tab[index = (n - 1) & hash]) != null) {
Node<K,V> node = null, e; K k; V v;
// 校驗連結串列頭結點是否是要刪除的節點
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
node = p;
// 判斷頭結點的下一個節點不為空
else if ((e = p.next) != null) {
// 如果節點是紅黑樹節點,呼叫紅黑樹的查詢方法
if (p instanceof TreeNode)
node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
else {
// 遍歷連結串列,找到 key 相同的節點並跳出迴圈
do {
if (e.hash == hash &&
((k = e.key) == key ||
(key != null && key.equals(k)))) {
node = e;
break;
}
p = e;
} while ((e = e.next) != null);
}
}
// 如果被移除的節點不為並且在匹配 value 的情況下,value 相等,則刪除節點
// (這個判斷寫的屬實繞!!!)
if (node != null && (!matchValue || (v = node.value) == value ||
(value != null && value.equals(v)))) {
// 如果節點是紅黑樹節點,則呼叫紅黑樹的移出方法
if (node instanceof TreeNode)
((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
// 如果移出的是連結串列的頭結點,則直接指向頭結點的下一個節點
else if (node == p)
tab[index] = node.next;
// 否則將 node 的上一個節點的下一個節點指向 node 的下一個節點
else
p.next = node.next;
// 修改次數加一
++modCount;
// map 的鍵值對數量減一
--size;
// 移出資料後的回撥,HashMap 是個空方法,LinkedHashMap 中有實現
afterNodeRemoval(node);
// 返回被移除的節點
return node;
}
}
return null;
}
/**
* 清空 map
*/
public void clear() {
Node<K,V>[] tab;
// 修改 map 的次數加一
modCount++;
// 判斷陣列不為空
if ((tab = table) != null && size > 0) {
// 將 size 設定為 0
size = 0;
// 遍歷陣列,將每個下標下對連結串列的引用設定為 null
for (int i = 0; i < tab.length; ++i)
tab[i] = null;
}
}
/**
* 判斷 map 中是否存在 value
*
* @param 是否存在的 value
* @return 如果返回 true 則標識存在一個或多個 key 的 value
* 與引數相等。
*/
public boolean containsValue(Object value) {
Node<K,V>[] tab; V v;
// 校驗 map 不為空
if ((tab = table) != null && size > 0) {
// 遍歷連結串列陣列
for (int i = 0; i < tab.length; ++i) {
// 遍歷每個下標對應的連結串列
for (Node<K,V> e = tab[i]; e != null; e = e.next) {
// 如果 value 相等,返回 true
if ((v = e.value) == value ||
(value != null && value.equals(v)))
return true;
}
}
}
return false;
}
/**
* 返回 map 中所有 key 的 set 集合
*/
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new KeySet();
keySet = ks;
}
return ks;
}
/**
* map 的 key Set 集合
*/
final class KeySet extends AbstractSet<K> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<K> iterator() { return new KeyIterator(); }
public final boolean contains(Object o) { return containsKey(o); }
public final boolean remove(Object key) {
return removeNode(hash(key), key, null, false, true) != null;
}
public final Spliterator<K> spliterator() {
return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super K> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
/**
* 返回 map 包含的所有 value 的集合
*/
public Collection<V> values() {
Collection<V> vs = values;
if (vs == null) {
vs = new Values();
values = vs;
}
return vs;
}
/**
* value 集合
*/
final class Values extends AbstractCollection<V> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<V> iterator() { return new ValueIterator(); }
public final boolean contains(Object o) { return containsValue(o); }
public final Spliterator<V> spliterator() {
return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super V> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.value);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
/**
* 返回一個 set 集合,儲存的是 map 中連結串列的每個節點
*/
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}
/**
* 節點集合
*/
final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<Map.Entry<K,V>> iterator() {
return new EntryIterator();
}
public final boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Node<K,V> candidate = getNode(hash(key), key);
return candidate != null && candidate.equals(e);
}
public final boolean remove(Object o) {
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Object value = e.getValue();
return removeNode(hash(key), key, value, true, true) != null;
}
return false;
}
public final Spliterator<Map.Entry<K,V>> spliterator() {
return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}
/**
* 通過 key 查詢 value,如果查詢不到則返回給定的預設 value
*/
@Override
public V getOrDefault(Object key, V defaultValue) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
}
/**
* 如果 key 不存在則儲存 value
*/
@Override
public V putIfAbsent(K key, V value) {
return putVal(hash(key), key, value, true, true);
}
/**
* 指定 key value 移出
*/
@Override
public boolean remove(Object key, Object value) {
return removeNode(hash(key), key, value, true, true) != null;
}
/**
* 指定 key 跟 oldValue,將 oldValue 替換成 newValue
*/
@Override
public boolean replace(K key, V oldValue, V newValue) {
Node<K,V> e; V v;
if ((e = getNode(hash(key), key)) != null &&
((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
e.value = newValue;
afterNodeAccess(e);
return true;
}
return false;
}
/**
* 指定 key,將其對應的 value 替換成傳入的 value
*/
@Override
public V replace(K key, V value) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) != null) {
V oldValue = e.value;
e.value = value;
afterNodeAccess(e);
return oldValue;
}
return null;
}
/**
* 如果 key 不存在或者對應的 value 為空,通過 mappingFunction 函式對 key 進行一定的處理生成 value,
* 並儲存,否則返回舊 value。(可用於構建本地快取)
*/
@Override
public V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
// 引數校驗
if (mappingFunction == null)
throw new NullPointerException();
// 獲取 key 的 hash 值
int hash = hash(key);
Node<K,V>[] tab; Node<K,V> first; int n, i;
int binCount = 0;
TreeNode<K,V> t = null;
Node<K,V> old = null;
// 判斷 table 是否需要擴容
if (size > threshold || (tab = table) == null ||
(n = tab.length) == 0)
n = (tab = resize()).length;
// 判斷 key 所在位置陣列對應的連結串列不為空
if ((first = tab[i = (n - 1) & hash]) != null) {
// 查詢節點
if (first instanceof TreeNode)
old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
else {
Node<K,V> e = first; K k;
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
old = e;
break;
}
++binCount;
} while ((e = e.next) != null);
}
V oldValue;
// 如果舊節點不為空且舊值不為空,則返回
if (old != null && (oldValue = old.value) != null) {
afterNodeAccess(old);
return oldValue;
}
}
// 通過 key 生成新的 value
V v = mappingFunction.apply(key);
// value 為空則返回
if (v == null) {
return null;
}
// 如果 key 存在且 value 為空
else if (old != null) {
// 設定新的 value 並返回
old.value = v;
afterNodeAccess(old);
return v;
}
// 如果是紅黑樹,從根節點插入新的 value
else if (t != null)
t.putTreeVal(this, tab, hash, key, v);
// 如果是連結串列,且 key 不存在,新增一個節點
else {
tab[i] = newNode(hash, key, v, first);
// 如果長度達到閾值則嘗試換將為紅黑樹
if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
}
// map 修改次數 + 1
++modCount;
// key value 對映個數 + 1
++size;
// 插入回撥
afterNodeInsertion(true);
// 返回新值
return v;
}
/**
* 如果 key 存在且 value 不為空,則通過 remappingFunction 函式對 key 和 value 進行處理,
* 生成新值,儲存並返回
*/
public V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
// 引數校驗
if (remappingFunction == null)
throw new NullPointerException();
Node<K,V> e; V oldValue;
// 獲取 key 的 hash 值
int hash = hash(key);
// 根據 key 獲取連結串列節點,並判斷節點和 value 不為空
if ((e = getNode(hash, key)) != null &&
(oldValue = e.value) != null) {
// 通過 key 和 oldValue 生成新值
V v = remappingFunction.apply(key, oldValue);
// 如果新值不為空,設定為新值並返回
if (v != null) {
e.value = v;
afterNodeAccess(e);
return v;
}
// 否則移除節點
else
removeNode(hash, key, null, false, true);
}
return null;
}
/**
* 通過 key 查詢舊值,然後通過 remappingFunction函式對 key 和舊值進行處理,生成新值,並儲存返回
*/
@Override
public V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
// 引數校驗
if (remappingFunction == null)
throw new NullPointerException();
// 獲取 key 的 hash 值
int hash = hash(key);
Node<K,V>[] tab; Node<K,V> first; int n, i;
int binCount = 0;
TreeNode<K,V> t = null;
Node<K,V> old = null;
// 判斷是否需要擴容
if (size > threshold || (tab = table) == null ||
(n = tab.length) == 0)
n = (tab = resize()).length;
// key 所在陣列位置的連結串列不為空
if ((first = tab[i = (n - 1) & hash]) != null) {
// 獲取與 key 相等的連結串列節點
if (first instanceof TreeNode)
old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
else {
Node<K,V> e = first; K k;
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
old = e;
break;
}
++binCount;
} while ((e = e.next) != null);
}
}
// 獲取舊值
V oldValue = (old == null) ? null : old.value;
// 根據舊值跟 key 生成新的 value
V v = remappingFunction.apply(key, oldValue);
// 如果 key 存在
if (old != null) {
// 如果新值不為空,則替換成新值
if (v != null) {
old.value = v;
afterNodeAccess(old);
}
// 否則移除節點
else
removeNode(hash, key, null, false, true);
}
// 如果 key 不存在且 value 不為空
else if (v != null) {
// 如果是紅黑樹則從根節點插入
if (t != null)
t.putTreeVal(this, tab, hash, key, v);
else {
// 新增連結串列節點
tab[i] = newNode(hash, key, v, first);
// 如果連結串列長度達到閾值,嘗試轉換成紅黑樹
if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
}
// map 修改次數 + 1
++modCount;
// key value 對映個數 + 1
++size;
// 新增資料回撥
afterNodeInsertion(true);
}
// 返回新值
return v;
}
/**
* 通過 key 查詢 value,如果 key 存在且舊值不為空,則通過 remappingFunction 函式對
* 舊值和引數 value 進行處理,生成新值並儲存,如果 key 存在但舊值為空,則新值就等於引數
* value,如果新值也為空,則移除 key 對應的節點,如果 key 不存在則插入引數 value
*/
@Override
public V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
// 引數驗證
if (value == null)
throw new NullPointerException();
if (remappingFunction == null)
throw new NullPointerException();
// 獲取 key 的 hash 值
int hash = hash(key);
Node<K,V>[] tab; Node<K,V> first; int n, i;
int binCount = 0;
TreeNode<K,V> t = null;
Node<K,V> old = null;
// 判斷是否需要擴容
if (size > threshold || (tab = table) == null ||
(n = tab.length) == 0)
n = (tab = resize()).length;
// 判斷 key 在陣列中所處的位置對應的連結串列不為空
if ((first = tab[i = (n - 1) & hash]) != null) {
// 查詢節點
if (first instanceof TreeNode)
old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
else {
Node<K,V> e = first; K k;
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
old = e;
break;
}
++binCount;
} while ((e = e.next) != null);
}
}
// 如果 key 存在
if (old != null) {
V v;
// 舊值不為空,通過 remappingFunction 函式對舊值和引數 value 進行出裡,
// 生成新值
if (old.value != null)
v = remappingFunction.apply(old.value, value);
// 否則新值等於引數 value
else
v = value;
// 新值不為空,設定新值
if (v != null) {
old.value = v;
afterNodeAccess(old);
}
// 新值為空,移除與 key 對應的節點
else
removeNode(hash, key, null, false, true);
return v;
}
// 如果 key 不存在
if (value != null) {
// 如果是紅黑樹,從根節點插入資料
if (t != null)
t.putTreeVal(this, tab, hash, key, value);
// 新增連結串列節點
else {
tab[i] = newNode(hash, key, value, first);
if (binCount >= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
}
// map 修改次數 + 1
++modCount;
// key value 對映個數 + 1
++size;
// 新增資料回撥
afterNodeInsertion(true);
}
// 返回 value
return value;
}
// 遍歷 map,通過 action 函式對每個 key,value 進行指定的業務邏輯處理
@Override
public void forEach(BiConsumer<? super K, ? super V> action) {
Node<K,V>[] tab;
// 引數校驗
if (action == null)
throw new NullPointerException();
// 判斷 map 不為空
if (size > 0 && (tab = table) != null) {
int mc = modCount;
// 遍歷連結串列陣列
for (int i = 0; i < tab.length; ++i) {
// 遍歷連結串列
for (Node<K,V> e = tab[i]; e != null; e = e.next)
// 對 key value 進行處理
action.accept(e.key, e.value);
}
// 如果 map 被修改,丟擲異常
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
/**
* 遍歷 map,通過 function 函式對每個 key value 進行處理生成新的 value 並設定
*/
@Override
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
Node<K,V>[] tab;
// 引數校驗
if (function == null)
throw new NullPointerException();
// 判斷 map 不為空
if (size > 0 && (tab = table) != null) {
int mc = modCount;
// 遍歷連結串列陣列
for (int i = 0; i < tab.length; ++i) {
// 遍歷連結串列
for (Node<K,V> e = tab[i]; e != null; e = e.next) {
// 通過 function 函式對 key value 進行處理,生成新值並設定
e.value = function.apply(e.key, e.value);
}
}
// 如果 map 被修改,則丟擲異常
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
/* ------------------------------------------------------------ */
// Cloning and serialization
/**
* 重寫 Object 的 clone 方法,淺拷貝一個新的 map
*
* @return 淺拷貝一個一個新 map
*/
@SuppressWarnings("unchecked")
@Override
public Object clone() {
HashMap<K,V> result;
try {
result = (HashMap<K,V>)super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
result.reinitialize();
result.putMapEntries(this, false);
return result;
}
/**
* 獲取負載係數
*/
final float loadFactor() { return loadFactor; }
/**
* 獲取連結串列陣列的長度
*/
final int capacity() {
return (table != null) ? table.length :
(threshold > 0) ? threshold :
DEFAULT_INITIAL_CAPACITY;
}
/**
* 序列化 map 方法,將 HashMap 例項的狀態儲存到 stream 中。
*/
private void writeObject(java.io.ObjectOutputStream s)
throws IOException {
int buckets = capacity();
// Write out the threshold, loadfactor, and any hidden stuff
s.defaultWriteObject();
s.writeInt(buckets);
s.writeInt(size);
internalWriteEntries(s);
}
/**
* 返序列化方法
*/
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
// Read in the threshold (ignored), loadfactor, and any hidden stuff
s.defaultReadObject();
reinitialize();
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new InvalidObjectException("Illegal load factor: " +
loadFactor);
s.readInt(); // Read and ignore number of buckets
int mappings = s.readInt(); // Read number of mappings (size)
if (mappings < 0)
throw new InvalidObjectException("Illegal mappings count: " +
mappings);
else if (mappings > 0) { // (if zero, use defaults)
// Size the table using given load factor only if within
// range of 0.25...4.0
float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
float fc = (float)mappings / lf + 1.0f;
int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
DEFAULT_INITIAL_CAPACITY :
(fc >= MAXIMUM_CAPACITY) ?
MAXIMUM_CAPACITY :
tableSizeFor((int)fc));
float ft = (float)cap * lf;
threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
(int)ft : Integer.MAX_VALUE);
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
table = tab;
// Read the keys and values, and put the mappings in the HashMap
for (int i = 0; i < mappings; i++) {
@SuppressWarnings("unchecked")
K key = (K) s.readObject();
@SuppressWarnings("unchecked")
V value = (V) s.readObject();
putVal(hash(key), key, value, false, false);
}
}
}
/**
* key、value、Entry 迭代器的父類
*/
abstract class HashIterator {
Node<K,V> next; // next entry to return
Node<K,V> current; // current entry
int expectedModCount; // for fast-fail
int index; // current slot
HashIterator() {
expectedModCount = modCount;
Node<K,V>[] t = table;
current = next = null;
index = 0;
if (t != null && size > 0) { // advance to first entry
do {} while (index < t.length && (next = t[index++]) == null);
}
}
public final boolean hasNext() {
return next != null;
}
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}
public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
/**
* key 迭代器
*/
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() { return nextNode().key; }
}
/**
* value 迭代器
*/
final class ValueIterator extends HashIterator
implements Iterator<V> {
public final V next() { return nextNode().value; }
}
/**
* Entry 迭代器
*/
final class EntryIterator extends HashIterator
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry<K,V> next() { return nextNode(); }
}
/**
* 並行迭代器 Q:為什麼沒有實現 Spliterator 介面呢?
*/
static class HashMapSpliterator<K,V> {
final HashMap<K,V> map;
Node<K,V> current; // current node
int index; // current index, modified on advance/split
int fence; // one past last index
int est; // size estimate
int expectedModCount; // for comodification checks
HashMapSpliterator(HashMap<K,V> m, int origin,
int fence, int est,
int expectedModCount) {
this.map = m;
this.index = origin;
this.fence = fence;
this.est = est;
this.expectedModCount = expectedModCount;
}
final int getFence() { // initialize fence and size on first use
int hi;
if ((hi = fence) < 0) {
HashMap<K,V> m = map;
est = m.size;
expectedModCount = m.modCount;
Node<K,V>[] tab = m.table;
hi = fence = (tab == null) ? 0 : tab.length;
}
return hi;
}
public final long estimateSize() {
getFence(); // force init
return (long) est;
}
}
/**
* key 的並行迭代器
*/
static final class KeySpliterator<K,V>
extends HashMapSpliterator<K,V>
implements Spliterator<K> {
KeySpliterator(HashMap<K,V> m, int origin, int fence, int est,
int expectedModCount) {
super(m, origin, fence, est, expectedModCount);
}
public KeySpliterator<K,V> trySplit() {
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid || current != null) ? null :
new KeySpliterator<>(map, lo, index = mid, est >>>= 1,
expectedModCount);
}
public void forEachRemaining(Consumer<? super K> action) {
int i, hi, mc;
if (action == null)
throw new NullPointerException();
HashMap<K,V> m = map;
Node<K,V>[] tab = m.table;
if ((hi = fence) < 0) {
mc = expectedModCount = m.modCount;
hi = fence = (tab == null) ? 0 : tab.length;
}
else
mc = expectedModCount;
if (tab != null && tab.length >= hi &&
(i = index) >= 0 && (i < (index = hi) || current != null)) {
Node<K,V> p = current;
current = null;
do {
if (p == null)
p = tab[i++];
else {
action.accept(p.key);
p = p.next;
}
} while (p != null || i < hi);
if (m.modCount != mc)
throw new ConcurrentModificationException();
}
}
public boolean tryAdvance(Consumer<? super K> action) {
int hi;
if (action == null)
throw new NullPointerException();
Node<K,V>[] tab = map.table;
if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
while (current != null || index < hi) {
if (current == null)
current = tab[index++];
else {
K k = current.key;
current = current.next;
action.accept(k);
if (map.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
}
}
return false;
}
public int characteristics() {
return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
Spliterator.DISTINCT;
}
}
/**
* value 的並行迭代器
*/
static final class ValueSpliterator<K,V>
extends HashMapSpliterator<K,V>
implements Spliterator<V> {
ValueSpliterator(HashMap<K,V> m, int origin, int fence, int est,
int expectedModCount) {
super(m, origin, fence, est, expectedModCount);
}
public ValueSpliterator<K,V> trySplit() {
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid || current != null) ? null :
new ValueSpliterator<>(map, lo, index = mid, est >>>= 1,
expectedModCount);
}
public void forEachRemaining(Consumer<? super V> action) {
int i, hi, mc;
if (action == null)
throw new NullPointerException();
HashMap<K,V> m = map;
Node<K,V>[] tab = m.table;
if ((hi = fence) < 0) {
mc = expectedModCount = m.modCount;
hi = fence = (tab == null) ? 0 : tab.length;
}
else
mc = expectedModCount;
if (tab != null && tab.length >= hi &&
(i = index) >= 0 && (i < (index = hi) || current != null)) {
Node<K,V> p = current;
current = null;
do {
if (p == null)
p = tab[i++];
else {
action.accept(p.value);
p = p.next;
}
} while (p != null || i < hi);
if (m.modCount != mc)
throw new ConcurrentModificationException();
}
}
public boolean tryAdvance(Consumer<? super V> action) {
int hi;
if (action == null)
throw new NullPointerException();
Node<K,V>[] tab = map.table;
if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
while (current != null || index < hi) {
if (current == null)
current = tab[index++];
else {
V v = current.value;
current = current.next;
action.accept(v);
if (map.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
}
}
return false;
}
public int characteristics() {
return (fence < 0 || est == map.size ? Spliterator.SIZED : 0);
}
}
/**
* 每個節點的並行迭代器
*/
static final class EntrySpliterator<K,V>
extends HashMapSpliterator<K,V>
implements Spliterator<Map.Entry<K,V>> {
EntrySpliterator(HashMap<K,V> m, int origin, int fence, int est,
int expectedModCount) {
super(m, origin, fence, est, expectedModCount);
}
public EntrySpliterator<K,V> trySplit() {
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid || current != null) ? null :
new EntrySpliterator<>(map, lo, index = mid, est >>>= 1,
expectedModCount);
}
public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
int i, hi, mc;
if (action == null)
throw new NullPointerException();
HashMap<K,V> m = map;
Node<K,V>[] tab = m.table;
if ((hi = fence) < 0) {
mc = expectedModCount = m.modCount;
hi = fence = (tab == null) ? 0 : tab.length;
}
else
mc = expectedModCount;
if (tab != null && tab.length >= hi &&
(i = index) >= 0 && (i < (index = hi) || current != null)) {
Node<K,V> p = current;
current = null;
do {
if (p == null)
p = tab[i++];
else {
action.accept(p);
p = p.next;
}
} while (p != null || i < hi);
if (m.modCount != mc)
throw new ConcurrentModificationException();
}
}
public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
int hi;
if (action == null)
throw new NullPointerException();
Node<K,V>[] tab = map.table;
if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
while (current != null || index < hi) {
if (current == null)
current = tab[index++];
else {
Node<K,V> e = current;
current = current.next;
action.accept(e);
if (map.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
}
}
return false;
}
public int characteristics() {
return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
Spliterator.DISTINCT;
}
}
/* ------------------------------------------------------------ */
// 支援 LinkedHashMap 的相關操作
/*
* The following package-protected methods are designed to be
* overridden by LinkedHashMap, but not by any other subclass.
* Nearly all other internal methods are also package-protected
* but are declared final, so can be used by LinkedHashMap, view
* classes, and HashSet.
*/
// 建立一個連結串列節點(非紅黑樹節點)
Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {
return new Node<>(hash, key, value, next);
}
// 替換節點
Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
return new Node<>(p.hash, p.key, p.value, next);
}
// 建立一個紅黑樹節點
TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
return new TreeNode<>(hash, key, value, next);
}
// 將連結串列節點替換為紅黑樹節點
TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
return new TreeNode<>(p.hash, p.key, p.value, next);
}
/**
* 將 map 初始化到預設狀態,在 clone 和 readObject 方法中呼叫
*/
void reinitialize() {
table = null;
entrySet = null;
keySet = null;
values = null;
modCount = 0;
threshold = 0;
size = 0;
}
// 在執行了某些操作後 LinkedHashMap 會使用這些方法做一些回撥操作
void afterNodeAccess(Node<K,V> p) { }
void afterNodeInsertion(boolean evict) { }
void afterNodeRemoval(Node<K,V> p) { }
// 只有 writeObject 方法呼叫,確保連結串列陣列及連結串列節點的順序
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
Node<K,V>[] tab;
if (size > 0 && (tab = table) != null) {
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next) {
s.writeObject(e.key);
s.writeObject(e.value);
}
}
}
}
/**
* 紅黑樹,具有五個基本性質
* 1. 每個節點只有一種顏色,要麼紅色,要麼黑色
* 2. 根節點是黑色
* 3. 葉節點(空節點)是黑色
* 4. 如果節點是紅色,那麼他的兩個子節點都是黑色
* 5. 任意的節點,從該節點到其所有後代葉節點的簡單路徑,均包含相同數目的黑色節點,
* 每次新增或刪除一個節點後,都有可能破壞紅紅黑樹的這幾個基本性質,因此每次操作後
* 都需要對其進行自底向上的修復操作,修復操作分為兩類:
* 1. 重新著色
* 2. 旋轉操作
* 該類還繼承了 Entry 類,說明該類還具有連結串列相關的特性。
*/
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
/*
* 父節點
*/
TreeNode<K,V> parent;
/*
* 左子節點
*/
TreeNode<K,V> left;
/*
* 右子節點
*/
TreeNode<K,V> right;
/*
* 下一個節點(連結串列特點)
*/
TreeNode<K,V> prev;
/*
* 節點顏色,true 紅色,false 黑色
*/
boolean red;
/**
* 建構函式,初始化一個樹節點
*/
TreeNode(int hash, K key, V val, Node<K,V> next) {
super(hash, key, val, next);
}
/**
* 獲取紅黑樹的根節點
*/
final TreeNode<K,V> root() {
for (TreeNode<K,V> r = this, p;;) {
if ((p = r.parent) == null)
return r;
r = p;
}
}
/**
* 將紅黑樹的根節點與紅黑樹所處的連結串列陣列的下標下儲存的節點對應,並設定紅黑樹的根節點為
* 連結串列的頭結點
*/
static <K,V> void moveRootToFront(Node<K,V>[] tab, TreeNode<K,V> root) {
// 連結串列陣列長度
int n;
// 引數校驗,root 跟 連結串列陣列均不為空
if (root != null && tab != null && (n = tab.length) > 0) {
// 重新計算紅黑樹 root 節點所處連結串列陣列的下標位置
int index = (n - 1) & root.hash;
// 下標對應的連結串列頭節點
TreeNode<K,V> first = (TreeNode<K,V>)tab[index];
// 如果紅黑樹的根節點和下標下的連結串列頭結點不一致
if (root != first) {
// 紅黑樹根節點的下一個節點
Node<K,V> rn;
// 將下標對應的節點更改為紅黑樹的根節點
tab[index] = root;
// 紅黑樹根節點的上一個節點
TreeNode<K,V> rp = root.prev;
// 如果根節點的上一個節點不為空
if ((rn = root.next) != null)
// 根節點的下一個節點的上一個節點指向根節點的上一個節點,
// 相當於把根節點從連結串列中刪除
((TreeNode<K,V>)rn).prev = rp;
// 如果根節點的上一個節點上一個節點不為空
if (rp != null)
// 根節點的上一個節點的下一個節點指向根節點的下一個節點
rp.next = rn;
// 連結串列的頭結點不為空
if (first != null)
// 連結串列的頭結點指向紅黑樹的根節點
first.prev = root;
// 根節點的下個節點指向原連結串列的頭結點
root.next = first;
// 根節點的上個節點設定為空
root.prev = null;
}
// 校驗資料正常
assert checkInvariants(root);
}
}
/**
* 紅黑樹查詢實現方法方法
*/
final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
// 複製當前物件到臨時變數
TreeNode<K,V> p = this;
do {
// 初始化臨時變數並賦值
int ph, dir; K pk;
TreeNode<K,V> pl = p.left, pr = p.right, q;
// 如果查詢的 hash 小於當前節點的 hash 值
// 則將左子樹賦值給臨時變數,繼續迴圈查詢
if ((ph = p.hash) > h)
p = pl;
// 如果查詢的 hash 大於當前節點的 hash 值
// 則將右子樹賦值給臨時變數,繼續迴圈查詢
else if (ph < h)
p = pr;
// 如果 key 相等,如果值相等, 則返回
else if ((pk = p.key) == k || (k != null && k.equals(pk)))
return p;
// 如果左子樹為空,則將右子樹賦值給臨時變數
else if (pl == null)
p = pr;
// 如果右子樹為空,則將左子樹賦值給臨時變數
else if (pr == null)
p = pl;
// 判斷 k 是否是 Comaprable 型別,如果是繼續判斷當前節點的
// key 跟 k 是否是同一型別,如果是則呼叫 compareTo 方法
// 比較兩值的大小
else if ((kc != null ||
(kc = comparableClassFor(k)) != null) &&
(dir = compareComparables(kc, k, pk)) != 0)
p = (dir < 0) ? pl : pr;
// 以上情況都不滿足的情況下則去右子樹節點下查詢
else if ((q = pr.find(h, k, kc)) != null)
return q;
// 左子樹節點下查詢
else
p = pl;
} while (p != null);
return null;
}
/**
* 通過 key 和 key 的 hash 值查詢紅黑樹節點
*/
final TreeNode<K,V> getTreeNode(int h, Object k) {
return ((parent != null) ? root() : this).find(h, k, null);
}
/**
* 在 hashCode 相等且 key 均沒有實現 Comparable 進行比較的情況下,
* 呼叫該方法比較兩個 key 的大小
*/
static int tieBreakOrder(Object a, Object b) {
int d;
if (a == null || b == null ||
(d = a.getClass().getName().
compareTo(b.getClass().getName())) == 0)
d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
-1 : 1);
return d;
}
/**
* 將連結串列轉換為紅黑樹
*/
final void treeify(Node<K,V>[] tab) {
// 初始化 root 節點的臨時變數
TreeNode<K,V> root = null;
// 迴圈當前紅黑樹,設定紅黑樹的相關屬性
for (TreeNode<K,V> x = this, next; x != null; x = next) {
// 賦值下一個節點給 next 變數
next = (TreeNode<K,V>)x.next;
// 初始化當前節點的左右子節點
x.left = x.right = null;
// 如果 root 為空(第一次遍歷),將當前物件設定為紅黑樹的根節點
if (root == null) {
// 根節點的父節點為空
x.parent = null;
// 根節點為黑色
x.red = false;
// x 賦值給 root 節點變數
root = x;
}
else {
// 將當前節點的 key 和 hash 賦值給臨時變數
K k = x.key;
int h = x.hash;
// key 的 Class 物件
Class<?> kc = null;
// 將當前節點插入到紅黑樹中,對 putTreeVal 方法進行了簡化,
// 因為是第一次插入,不會再去查詢 key 是否已經在紅黑樹中存在了,
// 進而提升一定的效率
for (TreeNode<K,V> p = root;;) {
int dir, ph;
K pk = p.key;
if ((ph = p.hash) > h)
dir = -1;
else if (ph < h)
dir = 1;
else if ((kc == null &&
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0)
dir = tieBreakOrder(k, pk);
TreeNode<K,V> xp = p;
if ((p = (dir <= 0) ? p.left : p.right) == null) {
x.parent = xp;
if (dir <= 0)
xp.left = x;
else
xp.right = x;
root = balanceInsertion(root, x);
break;
}
}
}
}
// 確保紅黑樹根節點與紅黑樹所處的連結串列陣列的下標下儲存的節點對應
// (保證每次搜尋時是從紅黑樹的根節點去搜尋啊!!!)
moveRootToFront(tab, root);
}
/**
* 將紅黑樹轉換為連結串列
*/
final Node<K,V> untreeify(HashMap<K,V> map) {
Node<K,V> hd = null, tl = null;
for (Node<K,V> q = this; q != null; q = q.next) {
Node<K,V> p = map.replacementNode(q, null);
if (tl == null)
hd = p;
else
tl.next = p;
tl = p;
}
return hd;
}
/**
* 紅黑樹版本的插入資料實現方法
*/
final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
int h, K k, V v) {
// 引數 k 的 Class 類引用
Class<?> kc = null;
// 當前節點以下所有節點是否都對引數 k 進行了查詢
boolean searched = false;
// 將 root 節點賦值給臨時變數
TreeNode<K,V> root = (parent != null) ? root() : this;
// 將 root 節點作為查詢的初始化節點
for (TreeNode<K,V> p = root;;) {
// 宣告臨時變數
int dir, ph; K pk;
// 賦值當前節點的 hash 值給臨時變數,並與要插入的
// k 的 hash 值進行比較,並將比較結果賦值給臨時變數
if ((ph = p.hash) > h)
dir = -1;
else if (ph < h)
dir = 1;
// 此時 hash 值應該是相等的,再去比較如果當前節點的 key 與插入的 key 相等,
// 則返回當前節點,因為有可能會出現 hash 值相等但 key 不相同的情況,
// 因此沒有單純的直接使用 hash 去比較是否相等,而是直接因為這樣可能會出現 bug
else if ((pk = p.key) == k || (k != null && k.equals(pk)))
return p;
// 在通過 hash 值跟 k 比較不出的情況下,則判斷插入的 key 是否
// 是 Comparable 型別,以及兩個類是否屬於同一型別,如果是則
// 呼叫 compareTo 比較兩個 key 的大小,如果無法比較則從當前
// 節點開始,查詢所有子節點是否存在 key 相等的情況,如果有就
// 直接返回。
else if ((kc == null &&
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0) {
// 如果以前沒有進行過搜尋,則查詢當前節點下所有子節點的 key
// 跟插入的 key 是否一致,如果一致則直接返回原節點
if (!searched) {
TreeNode<K,V> q, ch;
// 無論是否查到,都賦值給 searched 標識為已經查詢過
searched = true;
// 從當前節點的左右子節點開始查詢是否有子節點跟
// key 相等,如果有則直接返回
if (((ch = p.left) != null &&
(q = ch.find(h, k, kc)) != null) ||
((ch = p.right) != null &&
(q = ch.find(h, k, kc)) != null))
return q;
}
// 在 key 跟當前節點的 key 都不為空的情況下,通過類名去
// 比較大小,否則通過呼叫 System.identityHashCode 生
// 成的 hash 值去比較。Q:System.identityHashCode 的
// 具體作用?
dir = tieBreakOrder(k, pk);
}
// 將當前節點賦值給臨時變數
TreeNode<K,V> xp = p;
// 根據比較結果來判斷應該是插入到左右子節點中的哪一個,並判斷
// 其是否為空,如果為空則插入一個新的節點,否則更新迴圈條件,繼續比較
if ((p = (dir <= 0) ? p.left : p.right) == null) {
// 將當前節點的下一個節點賦值給臨時變數
Node<K,V> xpn = xp.next;
// 構建一個新節點
TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
// 如果 key 小於當前節點的 key 則賦值給左子樹,賦值賦值
// 給右子樹
if (dir <= 0)
xp.left = x;
else
xp.right = x;
// 將當前節點的下一節點更新為新插入的節點
xp.next = x;
// 將新插入的節點的父節點、上一個節點賦值為當前節點
x.parent = x.prev = xp;
// 更新 xpn 的上一個節點(真tm繞)
if (xpn != null)
((TreeNode<K,V>)xpn).prev = x;
// 新增節點後修復紅黑樹性質,並將根節點與陣列下標的引用關聯
moveRootToFront(tab, balanceInsertion(root, x));
return null;
}
}
}
/**
* 刪除給定的節點
*/
final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,
boolean movable) {
int n;
// 引數校驗
if (tab == null || (n = tab.length) == 0)
return;
// 當前節點在陣列中的下標
int index = (n - 1) & hash;
// 宣告連結串列的頭結點跟紅黑樹的頭節點,紅黑樹的頭結點的左子樹
TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl;
// 當前節點的下一個節點和上一個節點
TreeNode<K,V> succ = (TreeNode<K,V>)next, pred = prev;
// 如果當前節點頭結點,直接將陣列下標對應的節點改成當前節點的下一個節點
if (pred == null)
tab[index] = first = succ;
// 否則上一個節點的下一個節點改成當前節點的下一個節點
else
pred.next = succ;
// 如果下一個節點不為空,將下一個節點的上一個節點改成當前節點的上一個節點
if (succ != null)
succ.prev = pred;
// 如果連結串列的頭結點為空,則直接返回
if (first == null)
return;
// 如果 root 節點不是紅黑樹的根節點,則賦值為紅黑樹的根節點
if (root.parent != null)
root = root.root();
// 如果根節點為空或者根節點的左右子節點任意一個為空或者左子節點的
// 左子節點為空,則代表紅黑樹資料量太小,轉換為連結串列
if (root == null || root.right == null ||
(rl = root.left) == null || rl.left == null) {
tab[index] = first.untreeify(map);
return;
}
// p 被刪除的節點,pl p的左子節點,pr p的右子節點,
// replacement 在被刪除節點的做右子節點都不為空的情況下,是被刪除節點的後繼節點的後繼節點
// 否則便是被刪除節點的後繼節點
TreeNode<K,V> p = this, pl = left, pr = right, replacement;
// 如果左右子節點都不為空,尋找後繼節點(右子樹的最小值或者左子樹的最大值為後繼節點)和後繼節點的
// 後繼節點,並將後繼節點與被刪除節點交換位置
if (pl != null && pr != null) {
TreeNode<K,V> s = pr, sl;
// 迴圈遍歷右子樹,獲得最小值為後繼節點
while ((sl = s.left) != null)
s = sl;
// 交換顏色
boolean c = s.red; s.red = p.red; p.red = c;
// 後繼節點的右子節點
TreeNode<K,V> sr = s.right;
// 被刪除節點的父節點
TreeNode<K,V> pp = p.parent;
// 如果被刪除的節點是後繼節點的父節點
if (s == pr) {
// 將被刪除節點的父節點設定為後繼節點
p.parent = s;
// 後繼節點的右子節點設定為被刪除節點
s.right = p;
}
else {
// 後繼節點的父節點
TreeNode<K,V> sp = s.parent;
// 被刪除節點的父節點設定為後繼節點的父節點,並判斷不為空
if ((p.parent = sp) != null) {
// 如果後繼節點是父節點的左子節點,則替換為被刪除的節點
// 否則將右子節點替換為被刪除的節點
if (s == sp.left)
sp.left = p;
else
sp.right = p;
}
// 後繼節點的右子節點設定為被刪除節點的右子節點
if ((s.right = pr) != null)
// 並將右子節點的父子節點設定為後繼節點
pr.parent = s;
}
// 因為後繼節點是被刪除節點的右子樹的最小值,所以後繼節點肯定沒有左子節點,
// 因此直接將被刪除節點的左子節點設定為空
p.left = null;
// 將被刪除節點的右子節點替換為後繼節點的右子節點
if ((p.right = sr) != null)
sr.parent = p;
// 將後繼節點的左子節點設定為被刪除節點的左子節點
if ((s.left = pl) != null)
pl.parent = s;
// 將後繼節點的父節點設定為被刪除節點的父節點,如果父節點為空
// 則將後繼節點設定為紅黑樹的根節點
if ((s.parent = pp) == null)
root = s;
// 如果被刪除節點是原父節點的左子節點,則將後繼節點設定為父節點的左子節點
// 否則設定為右子節點
else if (p == pp.left)
pp.left = s;
else
pp.right = s;
// 因為後繼節點不存在左子節點,所以直接判斷右子節點是否為空,如果右子節點不為空
// 右子節點來替換後繼節點,否則被刪除節點替換後繼節點
if (sr != null)
replacement = sr;
else
replacement = p;
}
// 如果只有左子節點不為空,則將後繼節點設定為左子節點
else if (pl != null)
replacement = pl;
// 如果只有右子節點不為空,則將後繼節點設定為右子節點
else if (pr != null)
replacement = pr;
// 否則後繼節點就是被刪除節點本身
else
replacement = p;
// 如果後繼節點不是被刪除節點本身
if (replacement != p) {
// 後繼節點的父節點設定為被刪除節點的父節點
TreeNode<K,V> pp = replacement.parent = p.parent;
// 如果父節點為空,則將根節點設定為後繼節點
if (pp == null)
root = replacement;
// 將父節點與後繼節點關聯(此時已經將被刪除的節點從書中刪除)
else if (p == pp.left)
pp.left = replacement;
else
pp.right = replacement;
// 刪除被刪除節點對父節點、左右子節點的引用
p.left = p.right = p.parent = null;
}
// 根據被刪除節點的顏色,判斷是否修復紅黑樹的性質,因為如果被刪除的節點是黑色,
// 則可能導致該路徑比其他路徑少一顆黑色節點從而破壞紅黑樹性質,因此需要修復紅黑樹
TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);
// 如果後繼節點為被刪除結點本身,刪除與父節點的相互引用
if (replacement == p) {
TreeNode<K,V> pp = p.parent;
// 刪除對父節點的引用
p.parent = null;
// 父節點刪除對被刪除節點的引用
if (pp != null) {
if (p == pp.left)
pp.left = null;
else if (p == pp.right)
pp.right = null;
}
}
// 如果為 true, 確保紅黑樹根節點與紅黑樹所處的連結串列陣列的下標下儲存的節點對應
if (movable)
moveRootToFront(tab, r);
}
/**
* 將紅黑樹下的節點重新拆分
*
* @param map 當前 map
* @param tab 連結串列陣列
* @param index 紅黑樹在連結串列陣列的下標
* @param bit 舊的連結串列陣列長度
*/
final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
TreeNode<K,V> b = this;
// 原索引位置
TreeNode<K,V> loHead = null, loTail = null;
// 原索引 + bit 的位置
TreeNode<K,V> hiHead = null, hiTail = null;
// 各自的長度
int lc = 0, hc = 0;
for (TreeNode<K,V> e = b, next; e != null; e = next) {
// 更新 next 節點
next = (TreeNode<K,V>)e.next;
// 刪除 e 節點的 next 引用
e.next = null;
// 原索引位置
if ((e.hash & bit) == 0) {
// 頭部節點
if ((e.prev = loTail) == null)
loHead = e;
// 新增節點
else
loTail.next = e;
// 更新尾節點
loTail = e;
// 長度 + 1
++lc;
}
else {
// 更新頭結點
if ((e.prev = hiTail) == null)
hiHead = e;
// 新增節點
else
hiTail.next = e;
// 更新尾節點
hiTail = e;
// 長度 + 1
++hc;
}
}
// 原索引
if (loHead != null) {
// 如果長度紅黑樹節點個數小於閾值,轉換為連結串列
if (lc <= UNTREEIFY_THRESHOLD)
tab[index] = loHead.untreeify(map);
else {
// 將陣列下標對應的引用跟新為紅黑樹頭結點
tab[index] = loHead;
// 連結串列轉換為紅黑樹
if (hiHead != null)
loHead.treeify(tab);
}
}
// 原索引 + bit ,操作相同
if (hiHead != null) {
if (hc <= UNTREEIFY_THRESHOLD)
tab[index + bit] = hiHead.untreeify(map);
else {
tab[index + bit] = hiHead;
if (loHead != null)
hiHead.treeify(tab);
}
}
}
/**
* 左旋操作
*/
static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
TreeNode<K,V> p) {
TreeNode<K,V> r, pp, rl;
if (p != null && (r = p.right) != null) {
if ((rl = p.right = r.left) != null)
rl.parent = p;
if ((pp = r.parent = p.parent) == null)
(root = r).red = false;
else if (pp.left == p)
pp.left = r;
else
pp.right = r;
r.left = p;
p.parent = r;
}
return root;
}
/**
* 右旋操作
*/
static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,
TreeNode<K,V> p) {
TreeNode<K,V> l, pp, lr;
if (p != null && (l = p.left) != null) {
if ((lr = p.left = l.right) != null)
lr.parent = p;
if ((pp = l.parent = p.parent) == null)
(root = l).red = false;
else if (pp.right == p)
pp.right = l;
else
pp.left = l;
l.right = p;
p.parent = l;
}
return root;
}
/**
* 插入後修復紅黑樹性質
*/
static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
TreeNode<K,V> x) {
// 新插入的節點為空色
x.red = true;
// 初始化相關變數
for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
// xp 賦值為 x 節點的父節點,並且判斷如果 x 的父節點為空
// 則表示 x 為紅黑樹的根節點,將 x 節點設定為黑色,並返回
if ((xp = x.parent) == null) {
x.red = false;
return x;
}
// 將 xp 的父節點賦值為 xpp(xpp 為插入節點即 x 節點的爺爺節點),
// 如果 xp 為黑色或者 xpp 節點為空,則代表 xp 為根節點,
// 因此不需要進行修復,直接返回
else if (!xp.red || (xpp = xp.parent) == null)
return root;
// 如果父節點為爺爺節點的左子樹
if (xp == (xppl = xpp.left)) {
// 如果爺爺節點的右子樹不為空且也為紅色,此時 x 的節點為
// 紅色且父節點跟叔叔節點也為紅色,不符合紅黑樹性質,進行
// 重新著色修復
if ((xppr = xpp.right) != null && xppr.red) {
// x 的叔叔節點跟父節點設定為黑色
xppr.red = false;
xp.red = false;
// x 的爺爺節點設定為紅色
xpp.red = true;
// 將 x 更新為爺爺節點
x = xpp;
}
else {
// 如果叔叔節點為空或者為黑色,且 x 節點為父節點的右子節點
// 則先進行左旋操作
if (x == xp.right) {
// 左旋操作
root = rotateLeft(root, x = xp);
// 更新爺爺節點
xpp = (xp = x.parent) == null ? null : xp.parent;
}
// 如果父節點不為空
if (xp != null) {
// 父節點設定為黑色
xp.red = false;
// 如果爺爺節點不為空
if (xpp != null) {
// 爺爺節點設定為紅色
xpp.red = true;
// 進行右旋操作
root = rotateRight(root, xpp);
}
}
}
}
// 如果父節點為爺爺的節點的右子節點
else {
// 如果叔叔節點不為空且叔叔節點也為紅色,
// 直接進行重新著色來修復
if (xppl != null && xppl.red) {
// 叔叔節點跟父節點設定為黑色
xppl.red = false;
xp.red = false;
// 爺爺節點設定為紅色
xpp.red = true;
// x 節點更新為爺爺節點
x = xpp;
}
// 如果叔叔節點為空或者為黑色
else {
// 如果當前節點為父節點的左子節點
// 先進行右旋操作
if (x == xp.left) {
// 左旋操作
root = rotateRight(root, x = xp);
// 更新爺爺節點
xpp = (xp = x.parent) == null ? null : xp.parent;
}
// 如果父節點不為空
if (xp != null) {
// 父節點設定為黑色
xp.red = false;
// 爺爺節點不為空,則進行左旋操作
if (xpp != null) {
// 爺爺節點設定為紅色
xpp.red = true;
// 左旋操作
root = rotateLeft(root, xpp);
}
}
}
}
}
}
/**
* 刪除節點後修復紅黑樹的性質,引數 x 黑色(這個方法看的有點懵逼,肯定有問題,希望大家指出)
*/
static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
TreeNode<K,V> x) {
// 自底向上修復紅黑樹
for (TreeNode<K,V> xp, xpl, xpr;;) {
// 如果 x 節點為空或者為根節點,則停止修復
if (x == null || x == root)
return root;
// 如果 x 節點為根節點,直接將其設定為黑色
else if ((xp = x.parent) == null) {
x.red = false;
return x;
}
// 如果為紅色,設定為黑色
else if (x.red) {
x.red = false;
return root;
}
// 如果 x 節點是父節點的左子節點
else if ((xpl = xp.left) == x) {
// //有紅色的兄弟節點xpr,則父親節點xp必為黑色
if ((xpr = xp.right) != null && xpr.red) {
// 兄弟節點設定為黑色
xpr.red = false;
// 父節點設定為紅色
xp.red = true;
// 父節點左旋
root = rotateLeft(root, xp);
// 更新父節點跟兄弟節點
xpr = (xp = x.parent) == null ? null : xp.right;
}
// 如果兄弟節點為空,x 節點更新為父節點
if (xpr == null)
x = xp;
else {
TreeNode<K,V> sl = xpr.left, sr = xpr.right;
// 如果兄弟節點的左右子節點都不為空切都為黑色,兄弟節點
// 設定為紅色。
if ((sr == null || !sr.red) &&
(sl == null || !sl.red)) {
xpr.red = true;
x = xp;
}
else {
// 如果右子節點為空或者為黑色
if (sr == null || !sr.red) {
// 如果左子節點不為空,左子節點也設定為黑色
if (sl != null)
sl.red = false;
// 兄弟節點設定為紅色
xpr.red = true;
// 兄弟節點右旋
root = rotateRight(root, xpr);
// 更新父節點跟兄弟節點
xpr = (xp = x.parent) == null ?
null : xp.right;
}
// 如果兄弟節點不為空
if (xpr != null) {
// 如果父節點為空則兄弟節點為黑色,否則兄弟節點的顏色
// 設定為父節點的顏色
xpr.red = (xp == null) ? false : xp.red;
// 如果兄弟節點不為空,兄弟節點右節點設定為黑色
if ((sr = xpr.right) != null)
sr.red = false;
}
// 如果父節點不為空,父節點設定為黑色,並左旋
if (xp != null) {
xp.red = false;
root = rotateLeft(root, xp);
}
// x 節點更新為根節點
x = root;
}
}
}
// 如果 x 節點是父節點的右子節點,對稱操作
else {
if (xpl != null && xpl.red) {
xpl.red = false;
xp.red = true;
root = rotateRight(root, xp);
xpl = (xp = x.parent) == null ? null : xp.left;
}
if (xpl == null)
x = xp;
else {
TreeNode<K,V> sl = xpl.left, sr = xpl.right;
if ((sl == null || !sl.red) &&
(sr == null || !sr.red)) {
xpl.red = true;
x = xp;
}
else {
if (sl == null || !sl.red) {
if (sr != null)
sr.red = false;
xpl.red = true;
root = rotateLeft(root, xpl);
xpl = (xp = x.parent) == null ?
null : xp.left;
}
if (xpl != null) {
xpl.red = (xp == null) ? false : xp.red;
if ((sl = xpl.left) != null)
sl.red = false;
}
if (xp != null) {
xp.red = false;
root = rotateRight(root, xp);
}
x = root;
}
}
}
}
}
/**
* 校驗節點既符合連結串列特點也符合紅黑樹特點
*/
static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
tb = t.prev, tn = (TreeNode<K,V>)t.next;
if (tb != null && tb.next != t)
return false;
if (tn != null && tn.prev != t)
return false;
if (tp != null && t != tp.left && t != tp.right)
return false;
if (tl != null && (tl.parent != t || tl.hash > t.hash))
return false;
if (tr != null && (tr.parent != t || tr.hash < t.hash))
return false;
if (t.red && tl != null && tl.red && tr != null && tr.red)
return false;
if (tl != null && !checkInvariants(tl))
return false;
if (tr != null && !checkInvariants(tr))
return false;
return true;
}
}
}
複製程式碼