为什么HashSet的内部实现会创建虚拟对象以在HashMap中作为值插入而不是插入空值?
HashSet是使用HashMap实现的,当我们向HashSet添加任何e1时,如果e1不在集合中,它会在HashMap中添加(e1,new Object())。 我的问题是为什么他们插入新的Object(),当他们可以插入像(e1,null),这是更优化的方法,因为没有创建新的对象。 在这里插入空值有什么缺点吗?
每次将新键put
映射时, HashSet
都不会添加新的Object
。 它确实使用了Object
,但每次都使用相同的Object
。 此值在HashSet
源代码中命名为PRESENT
。
add
方法在内部HashMap
上调用put(key, PRESENT)
。 remove
方法调用内部HashMap
上的remove(key)
,但它必须返回一个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构造函数,则它不能包含任何空值。