java-hashmap 工作原理
HashMap有一個名為Entry類的內部類,其中包含鍵和值。還有一個叫做next的東西,你稍後就會知道。
static class Entry<K,V> implements Map.Entry<K,V> { final K key; V value; Entry<K,V> next; final int hash; ........ }
你應該知道HashMap將Entry例項儲存在陣列中,而不是作為鍵值對儲存。為了儲存值,都是使用HashMap的put()方法。讓我們深入研究一下,看看它是如何工作的。
Put()方法如何在內部工作?
程式碼如下:
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<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; }
首先,它檢查給定的金鑰是否為null。如果給定鍵為null,則它將儲存在零位置,因為null的Hashcode將為零。
然後,通過呼叫hashcode方法將hashcode應用於鍵. hashcode()。為了獲得陣列範圍內的值,將呼叫hash(key.hashCode()),它將對hashcode執行一些移位操作。
indexFor()方法用於獲取儲存條目物件的確切位置。
接下來是最重要的部分——如果兩個不同的物件具有相同的hashcode(例如Aa和BB將具有相同的hashcode),那麼它會儲存在同一個bucket中嗎?為了處理這個問題,讓我們考慮資料結構中的LinkedList。它將有一個“next”屬性,它總是指向下一個物件,就像條目類中的下一個屬性指向下一個物件一樣。使用具有相同hashcode的不同物件將彼此放置在一起。
在發生衝突的情況下,HashMap將檢查下一個屬性的值。如果為空,則將條目物件插入該位置。如果下一個屬性不為空,那麼它將保持迴圈執行,直到下一個屬性為空,然後將條目物件儲存在那裡。
如何在HashMap中防止重複鍵?
眾所周知,HashMap不允許重複鍵,即使在插入具有不同值的相同鍵時,也只返回最新的值。
LinkedList中的所有條目物件都有相同的hashcode,但HashMap使用equals()。這個方法檢查相等性,因此如果key.equals(k)為真,它將替換Entry類中的值物件,而不是鍵。通過這種方式,它可以防止插入重複的鍵。
Get()方法如何在內部工作?
將使用put()方法中應用的幾乎相同的邏輯來檢索值。
public V get(Object key) { if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); for (Entry<K,V> 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; }
首先,它獲取傳遞的密匙物件的雜湊碼,並查詢bucket位置。
- 如果找到了正確的bucket,它將返回該值。
- 如果沒有找到匹配,則返回null。
- 如果兩個鍵具有相同的Hashcode會發生什麼?
這裡將使用相同的衝突解決機制。key.equals(k)將檢查,直到它為真,如果為真,它將返回它的值。
轉載自 https://zhuanlan.zhihu.com/p/98883914