HashSet实现中的Null对象
在Java API中,HashSet的实现是使用Object作为内部HashMap的值,
// Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object(); public boolean add(E e) { return map.put(e, PRESENT)==null; }
但是HashMap允许它的值为null。 我认为没有必要填补价值,为什么需要这样做呢?
因为HashSet
契约指定remove()
如果指定的对象存在并被删除则返回true
。 为此,它使用包装的HashMap#remove()
返回删除的值。
如果要存储null
而不是对象,那么对HashMap#remove()
的调用将返回null
,这与尝试删除不存在的对象的结果和HashSet.remove()
的契约无法区分。无法实现。
但是HashMap允许它的值为null
当值完全由HashSet
控制时,为什么会这么重要? 这确保了与键相关联的唯一值是PRESENT
。 因此,如果map.put
返回null
,那只能是因为之前没有该键的条目。
该值就在那里,因为必须指定一些值,如果该值被指定为null
,那将是不好的 – 这将使得在add
调用之前更难判断是否存在值。 如果你要指定任何非空值,你也可以强制它一直是相同的值 – 例如,你不希望它阻止垃圾收集。
现在,如果你问为什么HashSet
是用HashMap
实现的,而不是一个根本不记录一个值的更有效的实现, 那是一个不同的问题,而且我没有答案。
在Java HashMap中,从对象到null的映射与根本不存在于映射中的对象不同。 考虑:
Object exists = new Object(); map.put(exists, null); System.out.println(map.contains(exists)) // "true" System.out.println(map.get(exists)) // "null" Object notMapped = new Object(); System.out.println(map.contains(notMapped)) // "false" System.out.println(map.get(notMapped)) // "null"
此外,HashMap.put()使用您放置的键返回旧值,在您的情况下为null(因为该键不在映射中,或者其值为null)。
使用Map
,如果你调用put(key, null)
,你就无法区分它们
- 密钥已经存在,映射为
null
- 该密钥没有映射
由于HashSet
add
委托add
到HashMap.put
,因此要求PRESENT
履行Set.add
的合同,如果对象已存在于Set
,则返回false
:
return map.put(e, PRESENT)==null;
我想再补充一点:
因为,HashSet add()方法的工作方式如下:
public boolean add(E e){
return map.put(e, PRESENT)==null; }
-
假设,如果PRESENT == null,那么当我们在HashMap中添加项时,它会返回null值
Object exists = new Object();
V value= map.put(exists,null); value will be null here
HashSet将返回 – > null == null – >> true
-
第二次,我们在hashMap中添加相同的键,其值为Null
map.put(exists,null);
return null == null – >> true它将允许hashSet中的重复项。这就是JDK Developers编写PRESENT对象的原因
注意==null
部分……………