向 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)。内部HashSetHashMapHashMap 确实替换了一些值,因为你们中的一些人已经指出了......但它真的替换了钥匙???不..这就是这里的诀窍。 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 中添加您的价值。

但是,HashMapMap 类型。这意味着每次添加条目时,都会添加一个键值对。

HashMap 中可以有重复的值,但不能有重复的键。在HashMap 中,新条目将替换旧条目。最新条目将位于HashMap

了解HashMap和HashSet之间的联系:

记住,HashMap 不能有重复的键。在幕后HashSet 使用HashMap

当您尝试将任何对象添加到HashSet 中时,此条目实际上存储为HashMap 中的键 - 与HashSet 幕后使用的HashMap 相同。由于这个底层的HashMap 需要一个键值对,所以为我们生成了一个虚拟值。

现在,当您尝试将另一个重复对象插入同一个 HashSet 时,它会再次尝试将其作为键插入位于下方的 HashMap 中。但是,HashMap 不支持重复。因此,HashSet 仍将导致只有一个该类型的值。附带说明一下,对于每个重复的键,由于为我们在 HashSet 中的条目生成的值是一些随机/虚拟值,因此根本不会替换键。它将被忽略,因为删除密钥并添加回相同的密钥(虚拟值相同)根本没有任何意义。

总结:

HashMap 允许重复 values,但不允许重复 keysHashSet 不能包含重复项。

想知道添加对象是否成功完成,可以查看调用.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:我不认为这是计划好的,我认为这只是HashSetHashMap的形式实现的效果。不过很难知道,除非您是这些课程的开发者之一。

以上是关于向 HashSet/HashMap 添加重复值是不是会替换先前的值的主要内容,如果未能解决你的问题,请参考以下文章

8-java安全基础——HashSet,HashMap源码分析

Java中HashSet,HashMap和HashTable的区别(转)

java set重复值是不存还是覆盖

HashSet和HashMap的区别

我就不信你还不懂HashSet/HashMap的底层原理

结合数据结构所学知识,简要说明Java语言中ArrayList,LinkedList,HashSet,HashMap四种结构各自的特点。