为什么 HashSet 的内部实现会创建虚拟对象作为值插入到 HashMap 中而不是插入空值?

问题描述 投票:0回答:4

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

java hashmap hashset
4个回答
19
投票
每次新键

HashSet

 进入地图时,
A
Object
不会添加新的
put
。它确实使用了
Object
,但每次都使用相同的
Object
。该值在
PRESENT
源代码中被命名为
HashSet

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


3
投票

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

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

public boolean remove(Object o) {
    return map.remove(o)==PRESENT;
}

如果使用

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


0
投票

例如如果将 HashSet 对象提供给 ConcurrentSkipListSet 构造函数,它不能包含任何 null 值。


0
投票

正如您所看到的,“PRESENT”被用作集合中所有元素的值,这非常有帮助,为什么? 当您调用 set.add(-) 时,它返回 true 或 false,这表明您添加的元素已经存在或不存在,这意味着在此添加操作之后是否存在已被替换的任何现有元素。如果他们将 null 用作 put 中 hashMap 的值部分,则无法识别是否有任何值已替换,因为如果值不存在,那么 map.put(-) 方法也会给出 null。当他们在 set.add(-) 方法中给出虚拟 PRESENT 值时,他们将从 map.put 方法中获取 PRESENT 值,这有助于确认新值已被设置并且旧值已在哈希集中被替换。

© www.soinside.com 2019 - 2024. All rights reserved.