12

在 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。我认为这不是填充值所必需的,那么为什么需要这样做呢?

4

6 回答 6

16

因为如果指定的对象存在并被删除,HashSet合约会指定remove()返回。true为此,它使用 WrappedHashMap#remove()返回删除的值。

如果您要存储null而不是对象,则调用 toHashMap#remove()将返回null,这与尝试删除不存在的对象的结果无法区分,并且HashSet.remove()无法履行合同。

于 2012-10-10T22:10:12.273 回答
6

但 HashMap 允许其值为 null

当值完全由 控制时,为什么这很重要HashSet?这确保了与键关联的唯一值是PRESENT. 因此,如果map.put返回null,那可能只是因为之前没有该键的条目。

该值就在那里,因为必须指定一些值,如果该值指定为null,那将是不好的 - 这将使得在调用 之前判断是否存在值变得更加困难add。如果你要指定任何非空值,你不妨强制它一直是相同的值——例如,你不希望它阻止垃圾收集。

现在,如果您要问为什么要HashSet根据HashMap而不是更有效的实现而不是根本不记录值来实现,那是一个不同的问题,我没有答案。

于 2012-10-10T22:10:05.873 回答
0

在 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() 使用您放置的键返回旧值,在您的情况下为空(因为该键不在地图中,或者它的值为空)。

于 2012-10-10T22:10:51.270 回答
0

使用 a Map,如果您调用put(key, null),则无法区分

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

由于HashSetadd委托HashMap.put,PRESENT需要履行 的合同,如果对象已经存在于 中Set.add,则返回:falseSet

return map.put(e, PRESENT)==null; 
于 2012-10-10T22:12:19.147 回答
0

我还想补充一件事:

因为,HashSet add() 方法的工作原理如下:

公共布尔添加(E e){

    return map.put(e, PRESENT)==null;
}
  1. 假设,如果 PRESENT==null 那么当我们第一次在 HashMap 中添加项目时,它返回null

    对象存在 = 新对象();

            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 开发人员编写 PRESENT 对象的原因

于 2018-05-17T03:56:38.653 回答
-1

注意==null部分......

于 2012-10-10T22:11:41.773 回答