java.util.HashMap
阿新 • • 發佈:2017-09-11
不同 resize clas corporate nbsp possible com 10個 eap
- HashMap 如何實現?
- put 做了什麽?
- get 做了什麽?
- 初始化容量,滿載率,擴展?
- hash?
- 類似的結構及相似處,不同點?
load factor 滿載率
capacity 容量
threshold 臨界值
import java.util.Map; public class Test { public static void main(String[] args) { Map<Key, String> map = new HashMap<Key, String>(); map.put(new Key("A"), "1"); map.put(new Key("B"), "2"); map.put(new Key("C"), "3"); System.out.println(map); } } class Key { private String name; Key(String name) { this.name = name; } @Override public int hashCode() { return 1; } @Overridepublic String toString() { return "Key [name=" + name + "]"; } }
import java.util.Map; public class Test { public static void main(String[] args) { Map<Key, Integer> map = new HashMap<Key, Integer>(); for (int i = 0; i < 11; i++) { map.put(new Key(System.nanoTime()), i); } System.out.println(map); } } class Key { private long name; Key(long name) { this.name = name; } @Override public int hashCode() { return 1; } @Override public String toString() { return "Key [name=" + name + "]"; } }
static final int TREEIFY_THRESHOLD = 8; static final int UNTREEIFY_THRESHOLD = 6; static final int MIN_TREEIFY_CAPACITY = 64;
控制treeify的臨界值是8 ,當bin中鏈大於8時,則嘗試treeify
- 1)如果此時表容量不足64,則會擴表。因此添加第9個元素時,由16->32 ,添加第10個元素時,由32->64
- 2)添加第11個元素時,此時轉為了TreeNode
==============================================
put
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K, V>[] tab; Node<K, V> p; int n, i; // 1 table 為空時重置大小 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; // 2 落到空bin 直接添加節點 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); // 3 落到非空bin ,判斷 a , b ,c, else { Node<K, V> e; K k; // a) header與入參key相同,替換舊值 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; // b) header是紅黑樹去添加樹節點 else if (p instanceof TreeNode) e = ((TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value); // c) header是鏈 else { // 遍歷鏈,逐項檢查 ,判斷 I ,II for (int binCount = 0;; ++binCount) { // I) 末尾追加節點並檢查是否需要轉為紅黑樹 if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } // II) key相同則替換舊值 返回 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; // 表中元素個數大於臨界值時,擴展表X2 if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
get
final Node<K, V> getNode(int hash, Object key) { Node<K, V>[] tab; Node<K, V> first, e; int n; K k; // table 存在,header節點存在 if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) { // 與 header 節點key相同,返回header 節點 if (first.hash == hash && ((k = first.key) == key || (key != null && key.equals(k)))) return first; // 如果存在header的子節點 if ((e = first.next) != null) { // 如果 header 是紅黑樹去取樹節點 if (first instanceof TreeNode) return ((TreeNode<K, V>) first).getTreeNode(hash, key); // 如果 header 是鏈 do { // 遍歷節點,找到相同key返回 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } // 未查到相同key return null; }
treeify
final void treeifyBin(Node<K, V>[] tab, int hash) { int n, index; Node<K, V> e; // 如果table達不到最小treeify 容量(64)則擴容X2 if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) resize(); // header 節點存在時 else if ((e = tab[index = (n - 1) & hash]) != null) { TreeNode<K, V> hd = null, tl = null; // 遍歷鏈將 Node -> TreeNode 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); } }
resize
/** * Initializes or doubles table size. If null, allocates in * accord with initial capacity target held in field threshold. * Otherwise, because we are using power-of-two expansion, the * elements from each bin must either stay at same index, or move * with a power of two offset in the new table. * * @return the table */ final Node<K, V>[] resize() { ... return newTab; }
hash
/** * Computes key.hashCode() and spreads (XORs) higher bits of hash * to lower. Because the table uses power-of-two masking, sets of * hashes that vary only in bits above the current mask will * always collide. (Among known examples are sets of Float keys * holding consecutive whole numbers in small tables.) So we * apply a transform that spreads the impact of higher bits * downward. There is a tradeoff between speed, utility, and * quality of bit-spreading. Because many common sets of hashes * are already reasonably distributed (so don‘t benefit from * spreading), and because we use trees to handle large sets of * collisions in bins, we just XOR some shifted bits in the * cheapest possible way to reduce systematic lossage, as well as * to incorporate impact of the highest bits that would otherwise * never be used in index calculations because of table bounds. */ static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
關於編寫方法時使用的縮略詞猜想
- mc = modCount
- tab = table
- bin = table[i]
- tl = tree left
- hd = header
- p = present
- i = index
- prev = previous
- next = next
- k = key
- val = value
- v = value
- n = length
- e = entry
- simple -> simplify
- tree -> treeify
- do -> undo
- untreeify -> untreeify
java.util.HashMap