![](/img/trans.png)
[英]HashSet doesnt allow duplicates but how to write logic for allowing duplicates
[英]How does HashSet not allow duplicates?
我正在經歷HashSet
的add
方法。 提到
如果此集合已包含該元素,則調用將保持該集合不變並返回 false。
但是add
方法是在內部保存HashMap
的值
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
HashMap
的put
方法指出
將指定值與此映射中的指定鍵相關聯。 如果映射先前包含鍵的映射,則舊值將被替換。
那么如果HashMap
的put
方法替換了舊值, HashSet
add
方法如何在出現重復元素的情況下保持集合不變呢?
PRESENT
只是一個虛擬值——集合並不真正關心它是什么。 什么是組做關於護理是地圖的鑰匙。 所以邏輯是這樣的:
Set.add(a):
map.put(a, PRESENT) // so far, this is just what you said
the key "a" is in the map, so...
keep the "a" key, but map its value to the PRESENT we just passed in
also, return the old value (which we'll call OLD)
look at the return value: it's OLD, != null. So return false.
現在, OLD == PRESENT
並不重要——請注意Map.put
不會更改鍵,只是映射到該鍵的值。 由於地圖的鍵是Set
真正關心的,所以Set
沒有改變。
事實上, Set
的底層結構已經發生了一些變化——它用(a, PRESENT)
替換了(a, OLD)
的映射。 但這不是從Set
的實現之外觀察到的。 (碰巧的是,這種變化甚至不是真正的變化,因為OLD == PRESENT
)。
您可能正在尋找的答案歸結為支持哈希映射將集合的元素映射到值PRESENT
的事實,該值在HashSet.java 中定義如下:
private static final Object PRESENT = new Object();
在HashMap.put
的源代碼中,我們有:
386 public V put(K key, V value) {
387 if (key == null)
388 return putForNullKey(value);
389 int hash = hash(key.hashCode());
390 int i = indexFor(hash, table.length);
391 for (Entry<K,V> e = table[i]; e != null; e = e.next) {
392 Object k;
393 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
394 V oldValue = e.value;
395 e.value = value;
396 e.recordAccess(this);
397 return oldValue;
398 }
399 }
400
401 modCount++;
402 addEntry(hash, key, value, i);
403 return null;
404 }
因為有問題的鍵已經存在,我們將在第 397 行獲取早期返回值。但您可能認為正在對第 395 行的映射進行更改,在該行中,我們似乎正在更改映射條目的值。 但是, value 的value
PRESENT
。 但是因為PRESENT
是靜態的和最終的,所以只有一個這樣的實例; 所以賦值e.value = value
實際上根本不會改變地圖,因此也不會改變集合!
更新:
一旦
HashSet
被初始化。
- 其中的所有項目都作為鍵存儲在HashMap
-HashMap
所有值只有一個PRESENT
對象,它是HashSet
一個靜態字段
正如你所看到的HashSet.add
方法添加元素到HashMap.put
作為重點而不是一個值。 值在HashMap
被替換而不是鍵。
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
e 是鍵,所以如果e已經存在put
將不會返回null
。 因此add
將返回 false。
用於put
JavaDoc:
與 key 關聯的先前值,如果沒有 key 的映射,則為 null。 (空返回也可以表明映射先前將空與鍵相關聯。)
來自 HashMap.put() 的 javadoc,“將指定值與此映射中的指定鍵相關聯。如果映射先前包含該鍵的映射,則替換舊值。”
這樣map值就會被替換,(它是HashSet類中的一個常量靜態字段,因此替換了同一個實例),而map鍵保持不變(實際上就是Set集合項)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.