詳解Java中HashMap的put方法實現原理

一、HashMap概述

HashMap是Java中常用的一種數據結構,它是基於哈希表實現的一種Map接口。在HashMap中,通過把key映射到數組上來實現快速訪問。接下來,我們將針對HashMap的數據結構和put方法進行詳解。

二、HashMap的數據結構

在看put方法實現原理之前,首先需要了解HashMap的數據結構,HashMap採用的數據結構是Array+LinkedList,即鏈表散列。它的核心在於把對象的關鍵字(key)映射到一個整數上,這個整數將作為一個索引,指向存儲這個關鍵字的實際對象的位置。這個對象可以在數組的這個位置上或者在對應的鏈表中。

public class HashMap extends AbstractMap
    implements Map, Cloneable, Serializable {
    /** 存儲元素的數組 */
    transient Node[] table; 
    /** HashMap的大小 */
    transient int size; 
    /** HashMap被修改的次數 */
    transient int modCount; 
    /** 閾值 */
    int threshold; 
    /** 加載因子 */
    final float loadFactor;
}

HashMap中存儲元素的數組是Node類型,其中Node類型是一個雙向鏈表結構,它的結構如下:

static class Node implements Map.Entry {
    final int hash; // 哈希值
    final K key; // 鍵
    V value; // 值
    Node next; // 指向下一個節點的引用
    ...
}

當在HashMap中添加元素的時候,它會計算出每個鍵(key)對應的哈希值,然後用哈希值除以數組長度,取得餘數,把鍵(key)放入到相應的數組元素中。在同一個數組元素中,保留了一個鏈表結構,用來存儲有相同哈希值的元素。

三、put方法實現原理

put方法是向HashMap中添加元素的方法,在了解了HashMap的數據結構後,我們來看看put方法的實現原理。

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

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)
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) {
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

HashMap的put方法通過哈希值計算和數組索引計算來存儲和定位元素。在執行put方法時,它首先計算出哈希值,然後找到對應的數組元素,如果該元素為null,則說明數組該位置沒有元素,直接把新元素插入到數組中。

接下來,如果該元素不為null,則需要看一下當前元素的哈希值是否與新元素相同,如果相同,則需要比較這兩個元素是否equals,如果equals返回true,則說明這個鍵已經存在於HashMap中,則把原來的value返回,否則,用新的value替換掉舊的value。

如果當前元素不為null,並且當前元素的哈希值與新元素的哈希值不同,則需要在當前元素的鏈表中往後查找,找到相同哈希值的元素,然後比較這兩個元素是否equals,如果equals返回true,則說明這個鍵已經存在於HashMap中,則把原來的value返回,否則,用新的value替換掉舊的value。

在查詢過程中,如果該元素為TreeNode類型,則說明該元素已經轉換為紅黑樹,此時,需要執行紅黑樹結構插入操作。

如果鏈表的長度達到閾值TREEIFY_THRESHOLD(默認值為8),則需要把鏈錶轉換為紅黑樹結構,從而提高查詢效率。

在把元素插入的過程中,如果HashMap中元素的個數達到了閾值,則需要擴大HashMap的容量,使得它可以容納更多的元素。在擴容過程中,較小容量的哈希表會複製到新表中,並且所有的元素都將會根據它們的哈希值重新分區到新表中。

四、小結

HashMap是Java中的一個重要數據結構,它是一個非常優秀的哈希表實現。在添加元素時,它採用哈希值計算和數組索引定位元素,還採用了鏈表散列和紅黑樹結構,使得它的查詢效率非常高。因此,在Java開發中,HashMap是一個常見的數據結構,尤其是存儲鍵值對的場景。而理解HashMap的實現原理,則是理解Java中哈希表實現的基礎。

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

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

相關推薦

  • ArcGIS更改標註位置為中心的方法

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

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

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

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

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

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

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

    編程 2025-04-29
  • Python中讀入csv文件數據的方法用法介紹

    csv是一種常見的數據格式,通常用於存儲小型數據集。Python作為一種廣泛流行的編程語言,內置了許多操作csv文件的庫。本文將從多個方面詳細介紹Python讀入csv文件的方法。…

    編程 2025-04-29
  • 使用Vue實現前端AES加密並輸出為十六進制的方法

    在前端開發中,數據傳輸的安全性問題十分重要,其中一種保護數據安全的方式是加密。本文將會介紹如何使用Vue框架實現前端AES加密並將加密結果輸出為十六進制。 一、AES加密介紹 AE…

    編程 2025-04-29
  • 用不同的方法求素數

    素數是指只能被1和自身整除的正整數,如2、3、5、7、11、13等。素數在密碼學、計算機科學、數學、物理等領域都有着廣泛的應用。本文將介紹幾種常見的求素數的方法,包括暴力枚舉法、埃…

    編程 2025-04-29
  • Python學習筆記:去除字符串最後一個字符的方法

    本文將從多個方面詳細闡述如何通過Python去除字符串最後一個字符,包括使用切片、pop()、刪除、替換等方法來實現。 一、字符串切片 在Python中,可以通過字符串切片的方式來…

    編程 2025-04-29
  • Harris角點檢測算法原理與實現

    本文將從多個方面對Harris角點檢測算法進行詳細的闡述,包括算法原理、實現步驟、代碼實現等。 一、Harris角點檢測算法原理 Harris角點檢測算法是一種經典的計算機視覺算法…

    編程 2025-04-29
  • 用法介紹Python集合update方法

    Python集合(set)update()方法是Python的一種集合操作方法,用於將多個集合合併為一個集合。本篇文章將從以下幾個方面進行詳細闡述: 一、參數的含義和用法 Pyth…

    編程 2025-04-29

發表回復

登錄後才能評論