12.23 HashMap是這樣在Java中工作的

HashMap問題在求職面試中很常見。這裡有一些關於hashmap在Java內部如何工作的深入解釋。

HashMap在內部如何工作已成為幾乎所有訪談中的一個普遍問題。幾乎每個人都知道如何使用HashMap或HashMap和Hashtable之間的區別。但是,當問題為" HashMap如何在內部工作?"時,許多人會不知道了。

這個問題的答案是,它是基於哈希原則工作的,但它並不像聽起來那麼簡單。哈希是一種使用算法為變量或屬性分配唯一代碼的機制,以便於檢索。真正的哈希機制應該總是返回相同的hashCode(),當它應用於相同的對象時。

接下來的問題是,"散列如何幫助在HashMap中存儲和檢索值?"許多人會說,值將存儲在bucket中,並使用鍵檢索。如果你認為它是這樣工作的,那你就大錯特錯了。為了證明這一點,讓我們看看HashMap類:

<code>/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
transient Entry[] table;/<code>


那麼HashMap中的Entry[]有什麼用呢?HashMap將對象存儲為條目實例,而不是鍵和值。

什麼是入門級?

HashMap有一個名為Entry類的內部類,其中包含鍵和值。還有一個叫做next的東西,你稍後就會知道。


<code> static class Entry implements Map.Entry 
{
final K key;
V value;
Entry next;
final int hash;
........
}
/<code>

你應該知道HashMap將Entry實例存儲在數組中,而不是作為鍵值對存儲。為了存儲值,都是使用HashMap的put()方法。讓我們深入研究一下,看看它是如何工作的。

Put()方法如何在內部工作?

代碼如下:

<code>public V put(K key, V value) 
{
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry 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;
}
/<code>

首先,它檢查給定的密鑰是否為null。如果給定鍵為null,則它將存儲在零位置,因為null的Hashcode將為零。

然後,通過調用hashcode方法將hashcode應用於鍵. hashcode()。為了獲得數組範圍內的值,將調用hash(key.hashCode()),它將對hashcode執行一些移位操作。

indexFor()方法用於獲取存儲條目對象的確切位置。

接下來是最重要的部分——如果兩個不同的對象具有相同的hashcode(例如Aa和BB將具有相同的hashcode),那麼它會存儲在同一個bucket中嗎?為了處理這個問題,讓我們考慮數據結構中的LinkedList。它將有一個"next"屬性,它總是指向下一個對象,就像條目類中的下一個屬性指向下一個對象一樣。使用具有相同hashcode的不同對象將彼此放置在一起。

在發生衝突的情況下,HashMap將檢查下一個屬性的值。如果為空,則將條目對象插入該位置。如果下一個屬性不為空,那麼它將保持循環運行,直到下一個屬性為空,然後將條目對象存儲在那裡。

如何在HashMap中防止重複鍵?

眾所周知,HashMap不允許重複鍵,即使在插入具有不同值的相同鍵時,也只返回最新的值。

<code>import java.util.HashMap;
import java.util.Map;
public class HashMapEg {
public static void main(String[] args) {
Map map = new HashMap();
map.put(1, "sam");
map.put(1, "Ian");
map.put(1, "Scott");
map.put(null, "asdf");
System.out.println(map);
}
}/<code>

對於上面的代碼,將得到輸出{null=asdf, 1=Scott},因為sam和Ian的值將被Scott替換。這是怎麼發生的呢?

LinkedList中的所有條目對象都有相同的hashcode,但HashMap使用equals()。這個方法檢查相等性,因此如果key.equals(k)為真,它將替換Entry類中的值對象,而不是鍵。通過這種方式,它可以防止插入重複的鍵。

Get()方法如何在內部工作?

將使用put()方法中應用的幾乎相同的邏輯來檢索值。

<code>public V get(Object key) 
{
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry e = table[indexFor(hash, table.length)];e != null;e = e.next)
{
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}
/<code>

首先,它獲取傳遞的密匙對象的散列碼,並查找bucket位置。

  1. 如果找到了正確的bucket,它將返回該值。
  2. 如果沒有找到匹配,則返回null。
  3. 如果兩個鍵具有相同的Hashcode會發生什麼?

這裡將使用相同的衝突解決機制。key.equals(k)將檢查,直到它為真,如果為真,它將返回它的值。

望本文能闡明麻煩的HashMap內部機制。學習愉快!


分享到:


相關文章: