请考虑下面的代码:
HashSet hs = new HashSet();
hs.add("hi"); -- (1)
hs.add("hi"); -- (2)
hs.size()
会返回1,因为HashSet
不允许有重复元素,所以只会存储一个元素。
我想知道如果添加了重复的元素,它会替换先前的元素还是不添加它?
另外,如果使用HashMap
做同样的操作会发生什么?
请考虑下面的代码:
HashSet hs = new HashSet();
hs.add("hi"); -- (1)
hs.add("hi"); -- (2)
hs.size()
会返回1,因为HashSet
不允许有重复元素,所以只会存储一个元素。
我想知道如果添加了重复的元素,它会替换先前的元素还是不添加它?
另外,如果使用HashMap
做同样的操作会发生什么?
HashSet
行为像一个 Set
,这意味着你直接将对象添加到 HashSet
中,它不能包含重复项。你只需直接在 HashSet
中添加你的值。HashMap
是一种 Map
类型。这意味着每次添加一个条目时,你都会添加一个键-值对。HashMap
中,你可以有重复的值,但不能有重复的键。在 HashMap
中,新条目将替换旧条目。最近的条目将出现在 HashMap
中。HashMap
不能有重复的键。在幕后,HashSet
使用一个 HashMap
。HashSet
中时,此条目实际上存储为 HashMap
中的一个键 - 这个与 HashSet
幕后使用的相同的 HashMap
。由于这个底层的 HashMap
需要一个键-值对,因此生成了一个虚拟值。HashSet
中时,它会再次尝试将其作为键插入到下面的 HashMap
中。然而,HashMap
不支持重复项。因此,HashSet
仍将只有一个该类型的值。顺便说一句,对于每个重复的键,由于在 HashSet 中为我们的条目生成的值是一些随机/虚拟值,因此根本不会替换键。它将被忽略,因为删除键并重新添加相同的键(虚拟值相同)根本没有任何意义。HashMap
允许重复的 值
,但不允许重复的 键
。
HashSet
不能包含重复项。为了检查添加对象是否成功完成,您可以检查调用.add()
时返回的布尔值,并查看它是否返回true
或false
。如果它返回true
,则已插入。
文档非常清晰: HashSet.add
不会 替换:
如果该集合中没有该元素,则将指定的元素添加到该集合中。更正式地说,如果此集合不包含任何元素 e2,使得 (e==null ? e2==null : e.equals(e2)),则将指定的元素 e 添加到该集合中。 如果该集合已经包含该元素,则调用不会改变集合并返回 false。
但是HashMap.put
会 替换:
如果该映射以前包含键的映射,则旧值将被替换。
http://docs.oracle.com/javase/6/docs/api/java/util/HashSet.html#add(E)
如果该集合中不存在指定元素,则将其添加到该集合中。更正式地说,如果该集合不包含任何元素e2使得(e==null ? e2==null : e.equals(e2)),则将指定元素e添加到该集合中。如果该集合已经包含该元素,则调用不会改变集合并返回false。如果我理解得不对,请纠正我,但你的意思是说,在字符串中,“Hi”==“Hi”并不总是为真(因为它们不一定是同一个对象)。
然而,你之所以得到1的答案是因为JVM会尽可能地重用字符串对象。在这种情况下,JVM正在重用字符串对象,从而覆盖了Hashmap / Hashset中的项目。
但是,你不能保证这种行为(因为它可能是具有相同值“Hi”的不同字符串对象)。你看到的行为只是由于JVM的优化。
HashMap
基本上包含Entry
,其中又包含Key(Object)
和Value(Object)
。内部上HashSet
是HashMap
,并且HashMap
确实会替换一些值,但它真正替换的是键吗?不是,这就是诀窍。HashMap
在底层HashMap
中将其值作为键保留,而该值仅仅是一个虚拟对象。因此,如果您尝试重新插入相同的值到HashMap(基础Map的键),它只会替换虚拟值而不是HashSet的键(底层Map的值)。
看下面的HashSet Class
代码:
public boolean [More ...] add(E e) {
return map.put(e, PRESENT)==null;
}
e 是 HashSet 的值,但是它是底层 map 的键。而且键值从未被替换。希望我已经澄清了混淆。
你需要先检查哈希映射中的put方法,因为HashSet由HashMap支持
HashMap
上进行检查,以查看在调用支持的map
上的put
之前是否已存在key
? - mystarrocksSet
的元素,这个元素永远不会被put()
操作替换。 - KeppilSet
的关键是元素,但刚刚意识到put()
只会覆盖值,而不是键。在这种情况下,它将再次与键一起放置相同的值,这可能比检查键是否存在并放置更好,也可能不是。无论哪种方式,我都明白它是如何工作的。 - mystarrocks