我正在使用add
的{{1}}方法。提到
如果此set已包含该元素,则调用将保持set不变并返回false。
但HashSet
方法在内部保存add
HashMap
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
put
方法表明
将指定的值与此映射中的指定键相关联。如果地图以前包含该键的映射,则替换旧值。
因此,如果HashMap
的{{1}}方法替换旧值,那么put
HashMap
方法如何在重复元素的情况下保持集不变?< /强>
答案 0 :(得分:32)
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, OLD)
与(a, PRESENT)
的映射。但是在Set
的实施之外,这是不可观察到的。 (事实上,这种变化甚至不是真正的变化,因为OLD == PRESENT
)。
答案 1 :(得分:8)
您可能正在寻找的答案归结为支持hashmap将集合的元素映射到HashSet.java中定义的值PRESENT
,如下所示:
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
的值为PRESENT
。但是因为PRESET
是静态的和最终的,所以只有一个这样的实例;所以赋值e.value = value
实际上并没有改变地图,因此也没有改变集合!
答案 2 :(得分:5)
正如您所看到的,HashSet.add
方法将元素作为键添加到HashMap.put
而不是值。值将替换为HashMap
而不是密钥。
答案 3 :(得分:3)
答案 4 :(得分:2)
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
e是关键,因此如果 e 已经存在,put
将不会返回null
。因此add
将返回false。
put
的JavaDoc:
与key关联的上一个值,如果没有key的映射,则返回null。 (null返回也可以指示映射先前将null与key关联。)
答案 5 :(得分:1)
从javadocs for HashMap.put(), “将指定的值与此映射中的指定键关联。如果映射先前包含键的映射,则替换旧值。”
因此地图值将被替换,(这是HashSet类中的常量静态字段,因此替换了相同的实例),并且地图键保持不变(实际上是Set集合项)< / p>