日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

HashMap的put方法(Java7)和putVal方法(Java8)

發(fā)布時(shí)間:2025/3/11 java 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HashMap的put方法(Java7)和putVal方法(Java8) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

    • 數(shù)組+鏈表:存在性能最壞情況O(n)
      • Java7的HashMap的put方法思路
    • 數(shù)組+鏈表+紅黑樹(shù):性能提高到O(logn)
      • Java8的HashMap的putVal方法思路

數(shù)組+鏈表:存在性能最壞情況O(n)

Java8以前,HashMap底層數(shù)據(jù)結(jié)構(gòu)采用數(shù)組+鏈表的結(jié)構(gòu)。
數(shù)組特點(diǎn):查詢快,增刪慢。
鏈表特點(diǎn):查詢慢,增刪較快。
HashMap:結(jié)合了數(shù)組和鏈表的優(yōu)勢(shì)。同時(shí)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);}

方法簡(jiǎn)述:
1、初始化HashMap,若Entry數(shù)組類(lèi)型的table為空,inflated(膨脹,擴(kuò)容意思)一個(gè)table,threshold默認(rèn)=初始容量=16;
2、對(duì)key求Hash值,然后再計(jì)算table下標(biāo);
3、如果沒(méi)有碰撞,即數(shù)組中沒(méi)有相應(yīng)的鍵值對(duì),直接放入桶(bucket)中,如果碰撞了,以鏈表的方式鏈接到后面;
4、如果鍵值對(duì)已經(jīng)存在就替換舊值;
5、如果桶滿了(容量16*加載因子0.75),就需要擴(kuò)容resize();

但是,存在壞情況:如果通過(guò)哈希散列運(yùn)算得到的是同一個(gè)值,即總是分配到同一個(gè)桶中,使某個(gè)桶的鏈表長(zhǎng)度很長(zhǎng)。
由于鏈表查詢需要從頭開(kāi)始遍歷,最壞情況下,HashMap性能變?yōu)镺(n)。

數(shù)組+鏈表+紅黑樹(shù):性能提高到O(logn)

Java8以后,HashMap底層數(shù)據(jù)結(jié)構(gòu)采用數(shù)組+鏈表+紅黑樹(shù)的結(jié)構(gòu)。
通過(guò)常量TREEIFY_THRESHOLD=8和UNTREEIFY_THRESHOLD=6來(lái)控制鏈表與紅黑樹(shù)的轉(zhuǎn)化。

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源碼基礎(chǔ)上增加了鏈表和紅黑樹(shù)的轉(zhuǎn)化。
如果鏈表長(zhǎng)度超過(guò)閾值8,就把鏈表轉(zhuǎn)換成紅黑樹(shù),如果鏈表長(zhǎng)度低于6,就把紅黑樹(shù)轉(zhuǎn)回鏈表。改變了最壞情況下O(n),性能提高到O(logn)。
注意:Java7中數(shù)組里的元素叫Entry,Java8及以后改名為Node(節(jié)點(diǎn))。

總結(jié)

以上是生活随笔為你收集整理的HashMap的put方法(Java7)和putVal方法(Java8)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。