【问题标题】:Why the internal implementation of HashSet creates dummy objects to insert as values in HashMap rather than inserting nulls?为什么 HashSet 的内部实现会创建虚拟对象以将其作为值插入 HashMap 中,而不是插入空值?
【发布时间】:2015-07-14 06:50:47
【问题描述】:

HashSet 是使用 HashMap 实现的,当我们向 HashSet 添加任何内容时,例如 e1,如果 e1 不存在于集合中,它会在内部添加 (e1,new Object()) 到 HashMap 中。我的问题是他们为什么要插入新的对象(),而他们本来可以像(e1,null)一样插入,这是更优化的方法,因为没有创建新的对象。在这里插入空值有什么缺点吗?

【问题讨论】:

  • 它不添加新对象。它添加了一个单独的值,用作集合中是否存在值的指示符。阅读源代码。
  • 在 Java 8 中,他们将其更改为 private static final Object PRESENT = new Object(); ,这是值。
  • 没有性能影响,因为对象是静态最终的,所以它只是一个常量,它将作为虚拟值工作
  • 你也可以在这里得到答案:stackoverflow.com/questions/12829163/…
  • @Sandeep 单个PRESENT 对象被用作HashSet 的内部HashMap 的值,至少可以追溯到Java 5。

标签: java hashmap hashset


【解决方案1】:

HashSet 不会在每次新键为 put 时添加新的 Object 到映射中。它确实使用了Object,但每次都使用相同的Object。此值在HashSet 源代码中被命名为PRESENT

add 方法在内部 HashMap 上调用 put(key, PRESENT)remove 方法在内部 HashMap 上调用 remove(key),但它必须返回一个 boolean 指示密钥是否存在。如果将null 存储为值,则HashSet 需要先调用containsKey,然后再调用remove,以确定密钥是否存在——额外开销。这里只有一个Object的内存开销,相当小。

【讨论】:

    【解决方案2】:

    我刚刚看了源码,看到了这段代码

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
    
    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }
    

    如果使用null 而不是PRESENT,这些将不起作用;在每种情况下,都需要一个额外的步骤。

    【讨论】:

      【解决方案3】:

      例如如果你给 ConcurrentSkipListSet 构造函数一个 HashSet 对象,它不能包含任何空值。

      【讨论】:

        猜你喜欢
        • 2013-12-01
        • 1970-01-01
        • 2010-09-19
        • 1970-01-01
        • 1970-01-01
        • 2021-05-06
        • 1970-01-01
        • 2023-03-16
        • 1970-01-01
        相关资源
        最近更新 更多