【轉】Java學習---HashMap和HashSet的內部工作機制

來源:互聯網
上載者:User

標籤:不同的   capacity   調用   string   離散   防止   ref   equals   面試   

【原文】https://www.toutiao.com/i6593863882484220430/

HashMap和HashSet的內部工作機制

HashMap 和 HashSet 內部是如何工作的?散列函數(hashing function)是什嗎?

HashMap 不僅是一個常用的資料結構,在面試中也是熱門話題。

Q1. HashMap 如何儲存資料?

A1. 以鍵/值對(key/value)形式儲存。你可以使用鍵(key)來存、取值。

Q2. HashMap 查詢時間的複雜度是怎樣的?

A2. 是O(n) = O(k * n)。如果 hashCode() 方法能向下面討論的那樣把資料分散到桶(bucket)中,那麼平均是O(1)。

Q3. HashMap 內部是如何儲存資料的?

A3. HashMap 使用後台數組(backing array)作為桶,並使用鏈表(linked list)儲存鍵/值對。

桶的後台數組:如下所示

1)使用鍵(key)和值(value)將一個對象放入 map 中時,會隱式調用 hashCode() 方法,返回雜湊值(hash code value),比如 123。兩個不同的鍵能夠返回一樣的雜湊值。良好的雜湊演算法(hashing algorithm)能夠將數值分散開。在上面的例子中,我們假設 (“John”,01/01/1956) 的鍵和 (“Peter”, 01/01/1995) 的鍵返回相同的雜湊值,都是123

2)當返回一個 hashCode,例如是 123,初始的 HashMap 容量為 10,它如何知道儲存到後台數組(backing array)的哪個索引(index)呢?HashMap 內部會調用 hash(int ) 和 indexFor(int h, int length) 方法。這被稱為雜湊函數(hashing function)。

簡要解釋下這個函數:

hashCode() % capacity

123 % 10 = 3

456 % 10 = 6

這表示,“hashCode = 123”儲存在備份數組的索引3上。

容量為 10 的情況下,你可能得到的數字在 09 之間。

一旦 HashMap 達到容量的 75%,也就是雜湊因子(hash factor)預設值 0.75,後台數組(backing array)的容量就會加倍,發生重散列(rehashing)為新的 20 的容量重新分配桶。

hashCode() % capacity

123 % 20 = 3

456 % 20 = 16

上面重散列的模數方法有一個缺陷。如果 hashCode 是負數會怎樣?負索引可不是你想要的。因此,一個改進的雜湊公式會移出符號位,然後再用模數(即 %)運算子計算剩餘部分。

(123 & 0x7FFFFFFF) % 20 = 3

(456 & 0x7FFFFFFF) % 20 = 16

這確保你得到的索引值為正數。如果你查看 Java 8 的 HashMap 源碼,它的實現使用以下方法:

a). 通過只抽取重要的低位,來防止不良離散值(poorer hashes)。

b). 根據雜湊碼hashCode)和容量capacity),來決定索引(index)。

實際的名稱值對(name value pairs)作為一個鍵/值對儲存在 LinkedList 中。

如所示,鍵/值對以鏈表形式儲存。兩個不同的鍵可以產生一樣的 hashCode,例如123,並儲存在同一個 bucket 中,理解這點至關重要。例如,上面例子中的 “John, 01/01/1956” 和 “Peter, 01/01/1995“ 。你如何只檢索 “John, 01/01/1956” 呢?此時你的 key 所屬類的 equals() 方法會被調用。它遍曆 bucket 為 “123” 的 LinkedList 中的每個條目,使用 equals() 方法找到並檢索出鍵為 “John, 01/01/1956” 的條目。這就是在你的類中實現 hashCode()equals() 方法重要性的原因。如果你使用一個現有的封裝類,如 Integer 或 String 作為鍵,它們已經實現了這兩個方法。如果你使用自己寫的類作為鍵,如 “John, 01/01/1956” 這樣含有名字和出生日期屬性的“MyKey”,你有責任正確地實現這些方法。

Q5. 為什麼恰當地設定 HashMap 的初始容量(initial capacity)是最佳實務?

A5. 這樣可以減少重散列的發生。

Q6. HashSet 內部如何儲存資料?

A6. HashSet 內部使用 HashMap 。它將元素儲存為鍵和值。(譯者註:HashSet 把儲存的值作為 key)

Q7. 為 Object 實現了一個糟糕的 hashcode() 會有什麼影響?

A7. 不同的對象調用 hashCode() 方法應該返回不同的值。如果不同的對象返回相同的值,會導致更多的鍵/值對儲存在同一個 bucket 中。這會降低 HashMap 和 HashSet 的效能

【轉】Java學習---HashMap和HashSet的內部工作機制

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.