Null Object in HashSet implementation

梦想与她 提交于 2019-12-17 16:21:15

问题


In the Java API, the implementation of HashSet is using an Object as a value for the inside 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;
}

but HashMap allows its value is null. I think that's not necessary to fill the value, so why is this needed?


回答1:


Because the HashSet contract specifies that remove() return true if the specified object existed and was removed. To do this, it uses the wrapped HashMap#remove() which returns the removed value.

If you were to store null instead of an object, then the call to HashMap#remove() would return null, which would be indistinguishable from the result of attempting to remove a non-existent object, and the contract of HashSet.remove() could not be fulfilled.




回答2:


but HashMap allows its value is null

Why would that matter, when the value is entirely controlled by HashSet? That ensures that the only value ever associated with a key is PRESENT. So if map.put returns null, that could only be because there was previously no entry for that key.

The value is just there because some value has to be specified, and if the value were specified as null, that would be bad - it would make it harder to tell whether there was a value before the call to add. If you're going to specify any non-null value, you might as well force it to be the same value all the time - you wouldn't want it to hold up garbage collection, for example.

Now if you're asking why HashSet is implemented in terms of HashMap rather than being a more efficient implementation which doesn't record a value at all, that's a different question, and one I don't have an answer to.




回答3:


In a Java HashMap, a mapping from an object to null is not the same as an object not being present in the map at all. Consider:

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"

Also, HashMap.put() returns the old value with the key you put, which in your case is null (either because that key wasn't in the map, or its value was null).




回答4:


With a Map, if you call put(key, null), you can't tell the difference between

  1. the key already existed, mapping to null
  2. there was no mapping for that key

Since HashSet's add delegates to HashMap.put, PRESENT is required to fulfil the contract of Set.add, which returns false if the object already existed in the Set:

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



回答5:


I want to add one more thing:

As, HashSet add() method works like below:

public boolean add(E e) {

    return map.put(e, PRESENT)==null;
}
  1. Suppose, if PRESENT==null then first time when we add item in HashMap then it return null value

    Object exists = new Object();

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

    HashSet will return -> null == null ->> true

  2. Second time when we add the same key in hashMap with value as Null

     map.put(exists,null);
    

    return null == null ->> true It will allows the duplicates in the hashSet.That's why JDK Developers write the PRESENT Object




回答6:


notice the ==null part...............



来源:https://stackoverflow.com/questions/12829163/null-object-in-hashset-implementation

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!