Ответ
HashSet в Java реализован на основе HashMap. Элементы HashSet хранятся как ключи в этой HashMap, а в качестве значения используется константный объект-заглушка.
Упрощенная схема из исходного кода OpenJDK:
public class HashSet<E> {
private transient HashMap<E, Object> map;
// Фиктивное значение для ассоциации с каждым ключом
private static final Object PRESENT = new Object();
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
// Успешное добавление, если ключа ранее не было (put возвращает null)
return map.put(e, PRESENT) == null;
}
public boolean contains(Object o) {
return map.containsKey(o);
}
public boolean remove(Object o) {
return map.remove(o) == PRESENT;
}
}
Следствия этой реализации:
- Производительность: Операции
add,remove,containsвыполняются за амортизированное O(1), как уHashMap. - Порядок элементов: Не гарантируется (зависит от хэш-функции и размера таблицы). Используйте
LinkedHashSetдля сохранения порядка вставки. - Дубликаты:
HashSetне позволяет дубликаты, так какHashMapне позволяет дубликаты ключей. - Null: Разрешает один элемент
null, так какHashMapразрешает один ключnull. - Итерация: Итератор по
HashSetпроходит по ключам внутреннейHashMap.