Java 容器系列(七):HashMap 原始碼分析01之建構函式、內部類
作為面試必問的 HashMap,是學習集合的重中之重,也是最難的一個。
1. HashMap 的類定義
- 繼承 抽象map,實現Map 介面,可複製,可克隆
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
1.1 HashMap 的構造方法
- HashMap 有 4 個構造方法,分別可用於指定載入因子,初始容量,初始化集合
/* 空構造,使用預設載入因子為 0.75 */
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
/* 指定 容量大小,使用預設載入因子,呼叫 */
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
/* 指定 容量大小,載入因子 */
public HashMap(int initialCapacity, float loadFactor) {
/* 若初始容量 < 0,跑錯 引數異常 */
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
/* 若指定容量過大,設定為最大容量 MAXIMUM_CAPACITY */
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
/* 若載入因子 < 0 || 傳入的float 是NaN 即(0.0f/0.0f), 報錯引數異常 */
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
/* 設定載入因子 */
this.loadFactor = loadFactor;
/* 初始化容量 */
this.threshold = tableSizeFor(initialCapacity);
}
/* 初始化一個集合,使用預設載入因子 */
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
}
1.2 HashMap 屬性定義
/* 版本號,用於初始化 */
private static final long serialVersionUID = 362498820763181265L;
/* 初始化容量為 16 */
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
/* 指定最大容量 2^30 */
static final int MAXIMUM_CAPACITY = 1 << 30;
/* 預設載入因子為 0.75 */
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;
/* 儲存 map 的桶,桶裡面才是連結串列,即 陣列 + 連結串列 */
transient Node<K,V>[] table;
/* 儲存 key,value 的集合 */
transient Set<Map.Entry<K,V>> entrySet;
/* 元素的個數 */
transient int size;
/* 修改次數 */
transient int modCount;
/* 臨界值 當實際大小超過臨界值時,會進行擴容threshold = 載入因子*容量 */
int threshold;
/* 載入因子 */
final float loadFactor;
1.3 HashMap 的內部類
1.1.1 Node
- 每一個新增的資料都會被封裝成一個 Node 節點,儲存 key,value,key的hash值,與下一個節點的指標
static class Node<K,V> implements Map.Entry<K,V> {
final int hash; // key 的hash值
final K key;
V value;
Node<K,V> next; // 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; } // 獲取 key 值
public final V getValue() { return value; } // 獲取 value 值
public final String toString() { return key + "=" + value; }
/* 重寫 hashcode 方法 */
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
/* 設定 value 值,返回舊值 */
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
/* 重寫 equals() 方法 */
public final boolean equals(Object o) {
if (o == this)
return true;
/* 若不是同一個地址值,則需要分別判斷 key,value 是否相等 */
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;
}
}
1.1.2 KeySet
- 儲存 Key 值的集合
final class KeySet extends AbstractSet<K> {
/* 返回集合個數 */
public final int size() { return size; }
/* 清空key,相當於清空 hashMap */
public final void clear() { HashMap.this.clear(); }
/* 獲取一個遍歷器 */
public final Iterator<K> iterator() { return new KeyIterator(); }
/* 是否包含某個key */
public final boolean contains(Object o) { return containsKey(o); }
/* 移除某個key,即移除某個節點 */
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);
}
/* 遍歷每一個key,執行 action 操作 */
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();
}
}
}
1.1.3 KeyIterator
- key值的遍歷迭代器
final class KeyIterator extends HashIterator
implements Iterator<K> {
/* 獲取到一個節點,再由節點獲取到 key 值 */
public final K next() { return nextNode().key; }
}
1.1.4 KeySpliterator
- Key值的分割遍歷器
static final class KeySpliterator<K,V>
extends HashMapSpliterator<K,V>
implements Spliterator<K> {
/* 構造器:param1: 分割的hashmap, param2:起始位置
param3: 分割位置, param4:分割個數,param5:期望的修改版本 */
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;
/* lo >= mid 即個數太少 || 當前節點為null 不分割,否則採用二分法擷取一半的長度 */
return (lo >= mid || current != null) ? null :
new KeySpliterator<>(map, lo, index = mid, est >>>= 1,
expectedModCount);
}
/* 遍歷當前遍歷器未遍歷的節點,執行 action 操作 */
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;
/* 1. tab != null && tab.length >= hi 即 tab 不為空且有元素
* 2. (i = index) >= 0 即起始位置 >= 0
* 3. i < (index = hi) || current != null 即 起始位置 < 終點位置 || 當前節點不為空
*/
if (tab != null && tab.length >= hi &&
(i = index) >= 0 && (i < (index = hi) || current != null)) {
Node<K,V> p = current;
current = null;
do {
/* p == null 即當前桶位沒有元素了,換下一個 */
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();
}
}
/* 對下一個元素進行 action 操作 */
public boolean tryAdvance(Consumer<? super K> action) {
int hi;
if (action == null)
throw new NullPointerException();
/* 獲取 table 陣列 */
Node<K,V>[] tab = map.table;
/* 陣列有值(即有桶位) && 桶個數 >= 擷取的長度 && 起始位置 >=0 */
if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
/* 當前節點不為空 || 起始位置 < 擷取位置 */
while (current != null || index < hi) {
/* 當前節點為空,換下一個桶 */
if (current == null)
current = tab[index++];
else {
/* 獲取當前key,將current往後移一位,執行 accept 操作,檢查 modCount版本,退出迴圈 */
K k = current.key;
current = current.next;
action.accept(k);
if (map.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
}
}
return false;
}
/* 特徵值: DISTINCT 表示無重複元素、SIZED 表示元素有精確個數 */
public int characteristics() {
/* fence < 0 即該迭代器沒有元素 || est == map.size 為遍歷或分解: 可以確定元素個數 */
return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
Spliterator.DISTINCT;
}
}
1.1.5 Values
- value 集合
final class Values extends AbstractCollection<V> {
/* 元素個數 */
public final int size() { return size; }
/* 清空 value 即 清空 hashMap */
public final void clear() { HashMap.this.clear(); }
/* 獲取 value 的迭代器 */
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);
}
/* value 值的遍歷,執行 action 操作 */
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();
}
}
}
1.1.6 ValueIterator
- 繼承 HashIterator,只是重寫了 next 方法
final class ValueIterator extends HashIterator
implements Iterator<V> {
/* 獲取下一節點,在獲取 value 值 */
public final V next() { return nextNode().value; }
}
1.1.7 ValueSpliterator
- value 值的分割迭代器
static final class ValueSpliterator<K,V>
extends HashMapSpliterator<K,V>
implements Spliterator<V> {
/* 傳入擷取的HashMap,起始位置,終點位置,個數,修改版本,呼叫父類構造即HashMapSpliterator */
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);
}
/* 遍歷執行 action 操作 */
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();
}
}
/* 下一個即將遍歷的元素 執行 action 操作 */
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;
}
/* 特徵值: SIZED 表示有精確個數 */
public int characteristics() {
/* fence < 0 即該迭代器沒有元素 || est == map.size 為遍歷或分解: 可以確定元素個數 */
return (fence < 0 || est == map.size ? Spliterator.SIZED : 0);
}
}
1.1.8 EntrySet
- 存放鍵值對的集合,前面的都是放key,或者 value,這裡將二者組合,變成一個 Map.Entry
final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
/* 不管是key,value,還是 EntrySet,在 HashMap 中的個數 size 都是相同的 */
public final int size() { return size; }
/* 清空 HashMap */
public final void clear() { HashMap.this.clear(); }
/* 獲取鍵值對Map.Entry<K,V> 的遍歷器(其實就是Node,因為Node實現了Map.Entry<K,V>) */
public final Iterator<Map.Entry<K,V>> iterator() {
return new EntryIterator();
}
/* 是否包含該鍵值對 */
public final boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
/* 強轉型別獲取key,根據key獲取Node,然後在比較 Node 與 e 是否相等 */
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) {
/* 先判斷 o 是否是 Map.Entry 的例項, 獲取 key,value 嘗試刪除節點,成功返回true,否則返回false */
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);
}
/* 鍵值對遍歷執行 action 操作 */
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();
}
}
}
1.1.9 EntryIterator
- 鍵值對的遍歷器
final class EntryIterator extends HashIterator
implements Iterator<Map.Entry<K,V>> {
/* 返回的Node 就是Map.Entry<K,V> */
public final Map.Entry<K,V> next() { return nextNode(); }
}
1.1.10 EntrySpliterator
- 鍵值對(Node)的分割遍歷器
static final class EntrySpliterator<K,V>
extends HashMapSpliterator<K,V>
implements Spliterator<Map.Entry<K,V>> {
/* 跟key、value 一樣,呼叫 HashMapSpliterator */
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);
}
/* 遍歷 執行 action 操作 */
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();
}
}
/* 對下一個即將遍歷的元素進行 action 操作 */
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;
}
/* 特徵值: DISTINCT 表示無重複元素、SIZED 表示元素有精確個數 */
public int characteristics() {
/* fence < 0 即該迭代器沒有元素 || est == map.size 為遍歷或分解: 可以確定元素個數 */
return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
Spliterator.DISTINCT;
}
}
1.1.11 HashIterator
abstract class HashIterator {
Node<K,V> next; // 下一個即將返回的節點
Node<K,V> current; // 當前節點
int expectedModCount; // 期待的修改版本
int index; // 當前節點的下標
/* 空構造:初始化引數 */
HashIterator() {
expectedModCount = modCount;
Node<K,V>[] t = table;
current = next = null;
index = 0;
/* 初始化賦值next */
if (t != null && size > 0) {
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; // 先儲存返回的 next
/* 檢查版本 */
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
/* null檢測,這就是為什麼推薦先判斷 hasNext() 的原因,避免報異常 NoSuchElementException */
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;
}
/* 移除當前元素,因為有 null 判斷,所以連續兩次呼叫會報異常 IllegalStateException */
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;
}
}
1.1.12 HashMapSpliterator
- hashMap 分割遍歷器
static class HashMapSpliterator<K,V> {
final HashMap<K,V> map; // 遍歷的 hashMap
Node<K,V> current; // 當前節點
int index; // 當前節點下標
int fence; // 遍歷器的最後一個元素的下標即
int est; // 遍歷器元素的個數
int expectedModCount; // 期待的修改版本
/* 全參構造,操作的HashMap,起始位置,結束位置,元素個數,期望版本 */
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;
/* 若 fence < 0,則當前屬性還未賦值 */
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;
}
/* 返回未遍歷的元素個數,先強制呼叫getFence(); 強制初始化引數 */
public final long estimateSize() {
getFence(); // force init
return (long) est;
}
}
1.1.13 總結
- HashMap 採用鍵值對(key,value) 的方式存資訊,底層使用 Node 節點儲存元素資訊,陣列 + 連結串列/紅黑樹 的方式儲存多個元素值。
- HashMap 提供了三種迭代器分別對 HashMap 的 key值、value值與Entry鍵值對進行遍歷,並且提供對應的分解迭代器。
相關文章
- 容器類原始碼解析系列(三)—— HashMap 原始碼分析(最新版)原始碼HashMap
- ConcurrentHashMap 原始碼分析03之內部類ReduceTaskHashMap原始碼
- dart系列之:dart類中的建構函式Dart函式
- Java容器系列-LinkedList 原始碼分析Java原始碼
- Java:HashMap原始碼分析JavaHashMap原始碼
- 死磕 java集合之HashMap原始碼分析JavaHashMap原始碼
- 原始碼分析之 HashMap原始碼HashMap
- Java原始碼篇之容器類——ArrayListJava原始碼
- Java容器類框架分析(1)ArrayList原始碼分析Java框架原始碼
- Java容器類框架分析(2)LinkedList原始碼分析Java框架原始碼
- Java容器類框架分析(5)HashSet原始碼分析Java框架原始碼
- Java 容器系列(六):LinkedList 原始碼分析02Java原始碼
- hive學習筆記之七:內建函式Hive筆記函式
- Vue原始碼: 建構函式入口Vue原始碼函式
- 類的建構函式和解構函式函式
- 原始碼|jdk原始碼之HashMap分析(一)原始碼JDKHashMap
- 原始碼|jdk原始碼之HashMap分析(二)原始碼JDKHashMap
- 人人都能懂的Vue原始碼系列(二)—Vue建構函式Vue原始碼函式
- vue原始碼解讀-建構函式Vue原始碼函式
- java基礎:HashMap — 原始碼分析JavaHashMap原始碼
- Java基礎——HashMap原始碼分析JavaHashMap原始碼
- java集合原始碼分析(六):HashMapJava原始碼HashMap
- 建構函式和類函式
- 死磕 jdk原始碼之HashMap原始碼分析JDK原始碼HashMap
- Java 集合系列之 LinkedList原始碼分析Java原始碼
- Java HashMap原理及內部儲存結構JavaHashMap
- Python學習系列之類的定義、建構函式 def __init__Python函式
- 容器類原始碼解析系列(四)---SparseArray分析(最新版)原始碼
- java併發之hashmap原始碼JavaHashMap原始碼
- 原始碼分析系列1:HashMap原始碼分析(基於JDK1.8)原始碼HashMapJDK
- php內建函式分析之array_fill_keys()PHP函式
- redux原始碼分析之四:compose函式Redux原始碼函式
- Java HashMap原始碼分析(含雜湊表、紅黑樹、擾動函式等重點問題分析)JavaHashMap原始碼函式
- SpringSecurity 原始碼分析之SecurityFilterchain的構建SpringGse原始碼FilterAI
- JDK1.8原始碼分析之HashMapJDK原始碼HashMap
- 容器類原始碼解析系列(一) ArrayList 原始碼分析——基於最新Android9.0原始碼原始碼Android
- JS 建構函式與類JS函式
- Java 容器學習之 HashMapJavaHashMap