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) ,你就无法区分它们

  1. 密钥已经存在,映射为null
  2. 该密钥没有映射

由于HashSet add委托addHashMap.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; } 
  1. 假设,如果PRESENT == null,那么当我们在HashMap中添加项时,它会返回null

    Object exists = new Object();

      V value= map.put(exists,null); value will be null here 

    HashSet将返回 – > null == null – >> true

  2. 第二次,我们在hashMap中添加相同的键,其值为Null

      map.put(exists,null); 

    return null == null – >> true它将允许hashSet中的重复项。这就是JDK Developers编写PRESENT对象的原因

注意==null部分……………