Я посмотрел на ваш вопрос, и мне потребовалось некоторое время, чтобы подумать о том, что вы сказали. Итак, вот мое мнение относительно реализации HashSet
.
Необходимо иметь фиктивный экземпляр, чтобы знать, присутствует или нет значение в наборе.
Взгляните на метод добавления
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
А теперь давайте посмотрим на возвращаемое значение пут
@ возвращает предыдущее значение, связанное с ключом, или ноль, если не было сопоставления для ключа. (Нулевой возврат также может указывать, что карта ранее ассоциировала нуль с ключом.)
Таким образом, объект PRESENT
используется только для представления того, что набор содержит значение e. Я думаю, вы спросили, почему бы не использовать null
вместо PRESENT
. Но вы не сможете различить, если запись ранее была на карте, потому что map.put(key,value)
всегда будет возвращать null
, и вы не сможете узнать, существовал ли ключ.
При этом можно утверждать, что они могли использовать реализацию, подобную этой
public boolean add(E e) {
if( map.containsKey(e) ) {
return false;
}
map.put(e, null);
return true;
}
Я полагаю, что они тратят 4 байта, чтобы избежать вычисления хэш-кода, поскольку он может быть дорогостоящим, для ключа два раза (если ключ будет добавлен).
Если вы задали вопрос о том, почему они использовали HashMap
, который бы тратил 8 байтов (из-за Map.Entry
) вместо какой-либо другой структуры данных, использующей похожую запись только из 4, тогда да, я бы сказал, что они сделали это по причинам, которые вы упомянули.