向 HashSet/HashMap 添加重复值是不是会替换先前的值
Posted
技术标签:
【中文标题】向 HashSet/HashMap 添加重复值是不是会替换先前的值【英文标题】:Does adding a duplicate value to a HashSet/HashMap replace the previous value向 HashSet/HashMap 添加重复值是否会替换先前的值 【发布时间】:2012-10-08 02:03:09 【问题描述】:请考虑以下代码:
HashSet hs = new HashSet();
hs.add("hi"); -- (1)
hs.add("hi"); -- (2)
hs.size()
将给出 1,因为 HashSet
不允许重复,因此只会存储一个元素。
我想知道如果我们添加了重复元素,那么它是替换前一个元素还是根本不添加它?
另外,对于同样的情况,使用HashMap
会发生什么?
【问题讨论】:
【参考方案1】:HashMap
基本上包含Entry
,随后包含Key(Object)
和Value(Object)
。内部HashSet
是HashMap
和HashMap
确实替换了一些值,因为你们中的一些人已经指出了......但它真的替换了钥匙???不..这就是这里的诀窍。 HashMap
将其值保留为底层HashMap
中的键,并且值只是一个虚拟对象。因此,如果您尝试在 HashMap 中重新插入相同的值(底层映射中的键)。它只是替换虚拟值而不是键( HashSet 的值)。
看下面HashSet类的代码:
public boolean [More ...] add(E e)
return map.put(e, PRESENT)==null;
这里 e 是 HashSet 的值,但底层 map.and 的键永远不会被替换。希望我能够消除混乱。
【讨论】:
【参考方案2】:换一种说法:当您将键值对插入到键已经存在的 HashMap 中时(在某种意义上,hashvalue() 给出相同的值,而 equal() 为真,但两个对象仍然可以不同以多种方式),键不会被替换,但值会被覆盖。键仅用于获取 hashvalue() 并使用它在表中查找值。 由于 HashSet 使用 HashMap 的键并设置(对用户而言)并不重要的任意值,因此 Set 的元素也不会被替换。
【讨论】:
【参考方案3】:您需要知道的第一件事是HashSet
的作用类似于Set
,这意味着您将对象直接添加到HashSet
,并且它不能包含重复项。您只需直接在HashSet
中添加您的价值。
但是,HashMap
是 Map
类型。这意味着每次添加条目时,都会添加一个键值对。
在HashMap
中可以有重复的值,但不能有重复的键。在HashMap
中,新条目将替换旧条目。最新条目将位于HashMap
。
了解HashMap和HashSet之间的联系:
记住,HashMap
不能有重复的键。在幕后HashSet
使用HashMap
。
当您尝试将任何对象添加到HashSet
中时,此条目实际上存储为HashMap
中的键 - 与HashSet
幕后使用的HashMap
相同。由于这个底层的HashMap
需要一个键值对,所以为我们生成了一个虚拟值。
现在,当您尝试将另一个重复对象插入同一个 HashSet
时,它会再次尝试将其作为键插入位于下方的 HashMap
中。但是,HashMap
不支持重复。因此,HashSet
仍将导致只有一个该类型的值。附带说明一下,对于每个重复的键,由于为我们在 HashSet 中的条目生成的值是一些随机/虚拟值,因此根本不会替换键。它将被忽略,因为删除密钥并添加回相同的密钥(虚拟值相同)根本没有任何意义。
总结:
HashMap
允许重复 values
,但不允许重复 keys
。
HashSet
不能包含重复项。
想知道添加对象是否成功完成,可以查看调用.add()
时返回的boolean
值,看看是返回true
还是false
。如果返回true
,则表示已插入。
【讨论】:
HashMap allows duplicate values
HashMap 用新值替换旧值。【参考方案4】:
由于HashSet是由HashMap备份的,所以需要先检查Hash map中的put方法
-
当您向 HashSet 添加重复值时,例如字符串“One”,
一个条目(“one”,PRESENT)将被插入到 Hashmap(对于所有
添加到集合中的值,如果是 Object 类型,该值将是“PRESENT”)
Hashmap 将条目添加到 Map 并返回值,本例中为
"PRESENT" 或 null 如果条目不存在。
如果 Hashmap 的返回值等于,则 Hashset 的 add 方法返回 true
null 否则为 false ,表示条目已存在...
【讨论】:
【参考方案5】:docs 对此非常清楚:HashSet.add
不替换:
如果指定元素尚不存在,则将其添加到此集合中。更正式地说,如果此集合不包含元素 e2,则将指定元素 e 添加到此集合中,使得 (e==null ? e2==null : e.equals(e2))。 如果该集合已经包含该元素,则调用保持该集合不变并返回 false。
但是HashMap.put
将替换:
如果映射先前包含键的映射,则替换旧值。
【讨论】:
【参考方案6】:HashSet 的情况,它不会取代它。
来自文档:
http://docs.oracle.com/javase/6/docs/api/java/util/HashSet.html#add(E)
"如果指定的元素不存在,则将其添加到该集合中。更正式地说,如果该集合不包含元素 e2,则将指定的元素 e 添加到该集合中,使得 (e==null ? e2==null : e .equals(e2))。如果该集合已经包含该元素,则调用保持该集合不变并返回 false。"
【讨论】:
【参考方案7】:如果我错了,请纠正我,但你得到的是字符串,“Hi”==“Hi”并不总是正确的(因为它们不一定是同一个对象)。
您得到 1 答案的原因是 JVM 将尽可能重用字符串对象。在这种情况下,JVM 正在重用字符串对象,从而覆盖 Hashmap/Hashset 中的项目。
但您不能保证这种行为(因为它可能是具有相同值“Hi”的不同字符串对象)。您看到的行为只是因为 JVM 的优化。
【讨论】:
【参考方案8】:对于HashMap
,它将旧值替换为新值。
在HashSet
的情况下,不插入项目。
【讨论】:
不确定我错过了什么,但source code 似乎另有说明?我看到他们没有检查支持HashMap
以查看key
是否已经存在,然后再调用支持map
上的put
?
@mystarrocks:关键是Set
的元素,它永远不会被put()
操作所取代。
啊我现在明白了。我知道键是Set
的元素,但刚刚意识到put()
只会覆盖值,而不是键。在这种情况下,再次将相同的值放在键旁边,这可能会或可能不会比检查键是否存在并放置更好。无论哪种方式,我都了解它是如何工作的。
只是好奇,为什么HashMap和HashSet会选择这样?
@HelinWang:我不认为这是计划好的,我认为这只是HashSet
以HashMap
的形式实现的效果。不过很难知道,除非您是这些课程的开发者之一。以上是关于向 HashSet/HashMap 添加重复值是不是会替换先前的值的主要内容,如果未能解决你的问题,请参考以下文章
8-java安全基础——HashSet,HashMap源码分析
Java中HashSet,HashMap和HashTable的区别(转)
结合数据结构所学知识,简要说明Java语言中ArrayList,LinkedList,HashSet,HashMap四种结构各自的特点。