Java 哈希集实现中的Null对象

Java 哈希集实现中的Null对象,java,hashset,Java,Hashset,在Java API中,HashSet的实现使用对象作为内部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。我认为这不是填

在Java API中,HashSet的实现使用对象作为内部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。我认为这不是填充值的必要条件,那么为什么需要这样做呢

但是HashMap允许其值为null

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

该值之所以存在,是因为必须指定一些值,如果该值被指定为
null
,那将是不好的-这将使在调用
add
之前很难判断是否存在值。如果您要指定任何非null值,那么不妨强制它始终为相同的值——例如,您不希望它停止垃圾收集


现在,如果你问为什么
HashSet
是按照
HashMap
实现的,而不是一个更高效的实现,根本不记录值,那是另一个问题,我没有答案。

因为
HashSet
契约指定
remove()
如果指定的对象存在并已删除,则返回
true
。为此,它使用包装的
HashMap#remove()
,返回删除的值


如果要存储
null
而不是对象,那么对
HashMap#remove()
的调用将返回
null
,这与尝试删除不存在的对象的结果无法区分,并且无法实现
HashSet.remove()
的约定,从对象到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)。

请注意,
==null
部分………..

带有
映射,如果调用
put(key,null)
,则无法区分

  • 密钥已存在,映射到
    null
  • 没有该键的映射
  • 由于
    HashSet
    add
    委托给
    HashMap.put
    ,因此需要
    PRESENT
    来履行
    Set.add
    的契约,如果
    集中已经存在对象,则返回
    false

    return map.put(e, PRESENT)==null; 
    

    我想补充一点:

    同样,HashSet add()方法的工作原理如下:

    公共布尔加法(E) {

  • 假设,如果PRESENT==null,那么当我们第一次在HashMap中添加项时,它返回null

    对象存在=新对象()

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

  • 第二次在hashMap中添加值为Null的相同键时

     map.put(exists,null);
    
    返回null==null->>true 它将允许hashSet中的重复项,这就是JDK开发人员编写当前对象的原因


  • 嗯,现在我想起来了,我也想知道为什么
    HashSet
    是用
    HashMap
    实现的……我本以为会有更好的方法来实现它。我的理解是,他们想改变它……但从来没有考虑过。不过,公平地说,如果你只是从条目和kep中删除value字段如果不是实现的其余部分不变,那么出于对齐的原因,您实际上不会节省任何速度或内存。您需要一个明显不同的实现来开始真正击败HashMap包装器实现,我想他们从来没有做到过。对齐参数对x86和x64(有压缩和没有压缩)都适用吗哎呀?如果是的话,我想这就可以解释了……不过感觉还是很奇怪。
            V  value=  map.put(exists,null);
                value will be null here
    
     map.put(exists,null);