HashSet 是使用 HashMap 实现的,当我们向 HashSet 添加任何内容(例如 e1)时,如果集合中不存在 e1,它会在内部将 (e1,new Object()) 添加到 HashMap 中。我的问题是为什么他们要插入 new Object(),而他们本来可以像 (e1,null) 那样插入,这是更优化的方法,因为没有创建新对象。在这里插入空值有什么缺点吗?
HashSet
进入地图时,A
Object
不会添加新的 put
。它确实使用了 Object
,但每次都使用相同的 Object
。该值在 PRESENT
源代码中被命名为 HashSet
。
add
方法在内部put(key, PRESENT)
上调用HashMap
。 remove
方法在内部 remove(key)
上调用 HashMap
,但它必须返回一个 boolean
指示密钥是否存在。如果 null
被存储为值,那么 HashSet
需要首先调用 containsKey
,然后调用 remove
,以确定密钥是否存在——额外的开销。这里,只有一个Object
的内存开销,这是非常小的。
我刚刚查看了源代码,看到了这段代码
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
如果使用
null
而不是 PRESENT
,这些将不起作用;在每种情况下,都需要额外的步骤。
例如如果将 HashSet 对象提供给 ConcurrentSkipListSet 构造函数,它不能包含任何 null 值。
正如您所看到的,“PRESENT”被用作集合中所有元素的值,这非常有帮助,为什么? 当您调用 set.add(-) 时,它返回 true 或 false,这表明您添加的元素已经存在或不存在,这意味着在此添加操作之后是否存在已被替换的任何现有元素。如果他们将 null 用作 put 中 hashMap 的值部分,则无法识别是否有任何值已替换,因为如果值不存在,那么 map.put(-) 方法也会给出 null。当他们在 set.add(-) 方法中给出虚拟 PRESENT 值时,他们将从 map.put 方法中获取 PRESENT 值,这有助于确认新值已被设置并且旧值已在哈希集中被替换。