Java中HashMap的put方法實現原理

一、數據結構介紹

HashMap是Java中常用的一種集合,是基於一定的hash算法實現的Key-value數據結構。HashMap類繼承於AbstractMap類,實現了Map接口。HashMap的底層實現是數組加鏈表或紅黑樹,通過key的hash值來找到其在數組中的位置,然後將其存儲在該位置的鏈表或紅黑樹中。

public class HashMap extends AbstractMap
    implements Map, Cloneable, Serializable {
        ...
    }

二、put方法

put方法是HashMap中最關鍵的方法之一,它負責將一個鍵值對存儲到Map中。put方法有兩個參數,第一個是key,第二個是value,該方法的返回值是被替換的value,如果之前沒有關聯的value則返回null。

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

可以看到,put方法的核心是putVal方法,該方法對外部不可見,它將key-value對插入到HashMap中,並且可以進行擴容和重新哈希處理。

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
            boolean evict) {
    Node[] tab; Node 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 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)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;
}

三、put實現原理

put方法主要通過以下幾個步驟實現:

  1. 如果table為null,或者table數組長度為0,執行resize方法進行初始化,否則直接用當前table數組存儲值。
  2. 通過(key.hash) & (n-1)計算key的哈希值,並找到它在table中需要存儲的位置 i。
  3. 檢查table[i]的這個位置是否已經有了值(e),如果沒有,就把新的鍵值對放到table[i]的位置上。
  4. 如果已經存在節點e,即table[i]位置已被佔用,則需要進一步判斷e和新插入元素的key是否相同,如果相同,則覆蓋原本的值,否則,需要判斷e所在節點的類型,如果是紅黑樹節點,則插入紅黑樹,否則在鏈表末尾追加節點。
  5. 如果鏈表長度超過TREEIFY_THRESHOLD(默認值為8)時,則將鏈錶轉化成紅黑樹。TREEIFY_THRESHOLD是為了避免鏈表過長導致查詢時間複雜度增加。
  6. 在插入節點後,判斷是否超過容量閾值(threshold),如果超過,進行擴容操作,將table數組長度翻倍。

四、實戰應用

下面是一個簡單的HashMap使用示例,通過put方法向map中存儲數據。

HashMap map = new HashMap();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
System.out.println(map.get(1)); //"one"
System.out.println(map.get(2)); //"two"
System.out.println(map.get(3)); //"three"

五、總結

本篇文章介紹了Java中HashMap的put方法實現原理,分別通過數據結構介紹、put方法、put實現原理和實戰應用等方面進行了詳細闡述。

為了保證HashMap的效率,需要在設計key的時候盡量避免哈希衝突,這樣可以減少鏈表的長度,提高HashMap的查詢效率。同時需要注意TREEIFY_THRESHOLD的值,這個值設置過小會導致鏈表膨脹成紅黑樹的過快,大大降低查詢性能。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/182034.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-11-24 06:17
下一篇 2024-11-24 06:17

相關推薦

  • Java JsonPath 效率優化指南

    本篇文章將深入探討Java JsonPath的效率問題,並提供一些優化方案。 一、JsonPath 簡介 JsonPath是一個可用於從JSON數據中獲取信息的庫。它提供了一種DS…

    編程 2025-04-29
  • java client.getacsresponse 編譯報錯解決方法

    java client.getacsresponse 編譯報錯是Java編程過程中常見的錯誤,常見的原因是代碼的語法錯誤、類庫依賴問題和編譯環境的配置問題。下面將從多個方面進行分析…

    編程 2025-04-29
  • Java騰訊雲音視頻對接

    本文旨在從多個方面詳細闡述Java騰訊雲音視頻對接,提供完整的代碼示例。 一、騰訊雲音視頻介紹 騰訊雲音視頻服務(Cloud Tencent Real-Time Communica…

    編程 2025-04-29
  • Java Bean加載過程

    Java Bean加載過程涉及到類加載器、反射機制和Java虛擬機的執行過程。在本文中,將從這三個方面詳細闡述Java Bean加載的過程。 一、類加載器 類加載器是Java虛擬機…

    編程 2025-04-29
  • Java Milvus SearchParam withoutFields用法介紹

    本文將詳細介紹Java Milvus SearchParam withoutFields的相關知識和用法。 一、什麼是Java Milvus SearchParam without…

    編程 2025-04-29
  • 解決.net 6.0運行閃退的方法

    如果你正在使用.net 6.0開發應用程序,可能會遇到程序閃退的情況。這篇文章將從多個方面為你解決這個問題。 一、代碼問題 代碼問題是導致.net 6.0程序閃退的主要原因之一。首…

    編程 2025-04-29
  • ArcGIS更改標註位置為中心的方法

    本篇文章將從多個方面詳細闡述如何在ArcGIS中更改標註位置為中心。讓我們一步步來看。 一、禁止標註智能調整 在ArcMap中設置標註智能調整可以自動將標註位置調整到最佳顯示位置。…

    編程 2025-04-29
  • Python中init方法的作用及使用方法

    Python中的init方法是一個類的構造函數,在創建對象時被調用。在本篇文章中,我們將從多個方面詳細討論init方法的作用,使用方法以及注意點。 一、定義init方法 在Pyth…

    編程 2025-04-29
  • Python創建分配內存的方法

    在python中,我們常常需要創建並分配內存來存儲數據。不同的類型和數據結構可能需要不同的方法來分配內存。本文將從多個方面介紹Python創建分配內存的方法,包括列表、元組、字典、…

    編程 2025-04-29
  • Java 8中某一周的周一

    Java 8是Java語言中的一個版本,於2014年3月18日發布。本文將從多個方面對Java 8中某一周的周一進行詳細的闡述。 一、數組處理 Java 8新特性之一是Stream…

    編程 2025-04-29

發表回復

登錄後才能評論