HashMap的put方法(Java7)和putVal方法(Java8)
目錄
- 數組+鏈表:存在性能最壞情況O(n)
- Java7的HashMap的put方法思路
- 數組+鏈表+紅黑樹:性能提高到O(logn)
- Java8的HashMap的putVal方法思路
數組+鏈表:存在性能最壞情況O(n)
Java8以前,HashMap底層數據結構采用數組+鏈表的結構。
數組特點:查詢快,增刪慢。
鏈表特點:查詢慢,增刪較快。
HashMap:結合了數組和鏈表的優勢。同時HashMap的操作是非Synchronized,因此效率比較高。
Java7的HashMap的put方法思路
put源碼:
public V put(K key, V value) {if (table == EMPTY_TABLE) {inflateTable(threshold);}if (key == null)return putForNullKey(value);int hash = hash(key);int i = indexFor(hash, table.length);for (Entry<K,V> e = table[i]; e != null; e = e.next) {Object k;if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {V oldValue = e.value;e.value = value;e.recordAccess(this);return oldValue;}}modCount++;addEntry(hash, key, value, i);return null;}addEntry源碼:
/*** Adds a new entry with the specified key, value and hash code to* the specified bucket. It is the responsibility of this* method to resize the table if appropriate.** Subclass overrides this to alter the behavior of put method.*/void addEntry(int hash, K key, V value, int bucketIndex) {if ((size >= threshold) && (null != table[bucketIndex])) {resize(2 * table.length);hash = (null != key) ? hash(key) : 0;bucketIndex = indexFor(hash, table.length);}createEntry(hash, key, value, bucketIndex);}方法簡述:
1、初始化HashMap,若Entry數組類型的table為空,inflated(膨脹,擴容意思)一個table,threshold默認=初始容量=16;
2、對key求Hash值,然后再計算table下標;
3、如果沒有碰撞,即數組中沒有相應的鍵值對,直接放入桶(bucket)中,如果碰撞了,以鏈表的方式鏈接到后面;
4、如果鍵值對已經存在就替換舊值;
5、如果桶滿了(容量16*加載因子0.75),就需要擴容resize();
但是,存在壞情況:如果通過哈希散列運算得到的是同一個值,即總是分配到同一個桶中,使某個桶的鏈表長度很長。
由于鏈表查詢需要從頭開始遍歷,最壞情況下,HashMap性能變為O(n)。
數組+鏈表+紅黑樹:性能提高到O(logn)
Java8以后,HashMap底層數據結構采用數組+鏈表+紅黑樹的結構。
通過常量TREEIFY_THRESHOLD=8和UNTREEIFY_THRESHOLD=6來控制鏈表與紅黑樹的轉化。
Java8的HashMap的putVal方法思路
putVal源碼:
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)n = (tab = resize()).length;if ((p = tab[i = (n - 1) & hash]) == null)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))))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 1sttreeifyBin(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 keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);return oldValue;}}++modCount;if (++size > threshold)resize();afterNodeInsertion(evict);return null;}在Java7源碼基礎上增加了鏈表和紅黑樹的轉化。
如果鏈表長度超過閾值8,就把鏈表轉換成紅黑樹,如果鏈表長度低于6,就把紅黑樹轉回鏈表。改變了最壞情況下O(n),性能提高到O(logn)。
注意:Java7中數組里的元素叫Entry,Java8及以后改名為Node(節點)。
總結
以上是生活随笔為你收集整理的HashMap的put方法(Java7)和putVal方法(Java8)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Undefined control se
- 下一篇: C#中合并两个lambda表达式