Объект Null в реализации 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 позволяет его значение равно нулю. Я думаю, что не нужно заполнять значение, так зачем это нужно?
Ответы
Ответ 1
Поскольку контракт HashSet
указывает, что remove()
возвращает true
, если указанный объект существует и был удален. Для этого используется обернутый HashMap#remove()
, который возвращает удаленное значение.
Если вы хотите хранить null
вместо объекта, то вызов HashMap#remove()
будет возвращать null
, который был бы неотличим от результата попытки удалить несуществующий объект, а контракт HashSet.remove()
не может быть выполнено.
Ответ 2
но HashMap позволяет его значение null
Почему это важно, когда значение полностью контролируется HashSet
? Это гарантирует, что единственным значением, когда-либо связанным с ключом, является PRESENT
. Поэтому, если map.put
возвращает null
, это может быть только потому, что ранее не было записи для этого ключа.
Значение только там, потому что нужно указать какое-то значение, и если значение было указано как null
, это было бы плохо - было бы сложнее сказать, было ли значение перед вызовом add
. Если вы укажете любое ненулевое значение, вы можете также заставить его быть одним и тем же значением все время - вы бы не хотели, чтобы он задерживал сборку мусора, например.
Теперь, если вы спрашиваете, почему HashSet
реализуется с точки зрения HashMap
, а не является более эффективной реализацией, которая вообще не записывает значение, это другой вопрос, и у меня нет ответ.
Ответ 3
В 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 (либо потому, что этот ключ не был на карте, либо его значение было нулевым).
Ответ 4
С помощью Map
, если вы вызываете put(key, null)
, вы не можете определить разницу между
- уже существовал ключ, сопоставление с
null
- для этого ключа не было сопоставления
Так как HashSet
add
делегирует HashMap.put
, PRESENT
требуется выполнить контракт Set.add
, который возвращает false
, если объект уже существует в Set
:
return map.put(e, PRESENT)==null;
Ответ 5
обратите внимание на часть ==null
...............