【问题标题】: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 会发生什么?

【问题讨论】:

    标签: java hashmap duplicates hashset


    【解决方案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方法

        1. 当您向 HashSet 添加重复值时,例如字符串“One”,
        2. 一个条目(“one”,PRESENT)将被插入到 Hashmap(对于所有 添加到集合中的值,如果是 Object 类型,该值将是“PRESENT”)
        3. Hashmap 将条目添加到 Map 并返回值,本例中为 "PRESENT" 或 null 如果条目不存在。
        4. 如果 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的形式实现的效果。不过很难知道,除非您是这些课程的开发者之一。
                猜你喜欢
                • 1970-01-01
                • 2018-05-15
                • 2019-10-02
                • 1970-01-01
                • 2021-04-05
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-04-03
                相关资源
                最近更新 更多