HashMap原始碼閱讀(原始碼閱讀四)
阿新 • • 發佈:2019-03-08
jdk版本為1.8.0_131
初始化(沒有任何操作,只是做了各種引數的初始化預設值的設定)
public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted }
那貓膩應該都在put和get方法裡面
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
/** * Implements Map.put and related methods * * @param hash hash for key * @param key the key * @param value the value to put * @param onlyIfAbsent if true, don't change existing value * @param evict if false, the table is in creation mode. * @return previous value, or null if none */ 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)//hash表為空或者長度為空 初始化 n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null)//hash陣列下標為空 new一個節點 tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))//hash值和key都一樣 替換 e = p; 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; }
transient Node<K,V>[] table;//key hash後的陣列下標
從上面,能看出來維護一個table陣列
主要流程簡述:
1.對key進行hash,作為陣列下標,儲存到table中
2.如果該陣列下標沒有值,新增新的node節點
3.如果有值,判斷key是否也一直,一致直接替換
4.key不一致單節點轉為連結串列,新增next節點
5.當這個連結串列的數量超出某個值是,轉換為樹結構
/** l連結串列轉樹結構 * Replaces all linked nodes in bin at index for given hash unless * table is too small, in which case resizes instead. */ 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(); else if ((e = tab[index = (n - 1) & hash]) != null) { TreeNode<K,V> hd = null, tl = null; do { TreeNode<K,V> p = replacementTreeNode(e, null); if (tl == null) hd = p; else { p.prev = tl; tl.next = p; } tl = p; } while ((e = e.next) != null); if ((tab[index] = hd) != null) hd.treeify(tab); } }
接下來就是get方法這個就比較簡單了,根據上面的儲存邏輯去獲取資料
final Node<K,V> getNode(int hash, Object key) { Node<K,V>[] tab; Node<K,V> first, e; int n; K k; if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) { if (first.hash == hash && // always check first node ((k = first.key) == key || (key != null && key.equals(k)))) return first; if ((e = first.next) != null) { if (first instanceof TreeNode) return ((TreeNode<K,V>)first).getTreeNode(hash, key); do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } }