Использует ли HashMap HashSet для хранения своих ключей?

1

Мне интересно, использует ли HashMap HashSet для хранения своих ключей. Я бы предположил, что это так, потому что HashMap будет соответствовать HashSet, а TreeMap будет соответствовать TreeSet.

Я посмотрел исходный код для класса HashMap, и этот метод возвращает AbstractSet, реализованный каким-то Iterator.

Кроме того... когда я пишу

    HashMap map = new HashMap();

    if(map.keySet() instanceof HashSet){
        System.out.println("true");
    }

Вышеприведенный оператор if никогда не запускается. Теперь я не уверен

Может ли кто-нибудь объяснить, как HashMap хранит свои ключи?

  • 0
    Нет, [в Oracle JDK] это не так. Посмотрите на реализацию (на GrepCode) , которая должна сделать довольно очевидным, что HashMap не использует и лежит в основе HashSet. (Кроме того, из API видно, что HashMap не является подтипом HashSet и даже не соответствует интерфейсу Set.)
  • 0
    (Очень Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; , см. Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; член в HashMap - используется массив, а не HashSet.)
Показать ещё 7 комментариев
Теги:
hashmap

4 ответа

2
Лучший ответ

Вы задаете два вопроса:

  1. Использует ли HashMap HashSet для хранения своих ключей?
  2. HashMap.keySet() возвращает HashSet?

Ответ на оба вопроса - нет, и по той же причине, но нет технической причины, препятствующей 1 или 2. быть истинным.

HashSet на самом деле является оберткой вокруг HashMap; HashSet имеет следующую переменную-член:

private transient HashMap<E,Object> map;

Он добавляет значение PRESENT sentinel в качестве значения карты, когда объект добавляется к набору.

Теперь HashMap хранит данные в массиве объектов Entry содержащих пары Key, Value:

transient Entry<K,V>[] table;

И метод keySet() возвращает экземпляр внутреннего класса KeySet:

public Set<K> keySet() {
  Set<K> ks = keySet;
  return (ks != null ? ks : (keySet = new KeySet()));
}

private final class KeySet extends AbstractSet<K> {
  // minimal Set implementation to access the keys of the map
}

Поскольку KeySet является частным внутренним классом, насколько вы должны беспокоиться, это просто произвольная реализация Set.

Как я уже сказал, нет причин, по которым это должно быть. Вы могли бы абсолютно реализовать класс Map который использовал HashSet внутренне, а затем вернуть Map HashSet из .keySet(). Однако это было бы неэффективно и сложно кодировать; существующая реализация является более надежной и более эффективной, чем наивные реализации Map/Set.

Фрагменты кода, взятые из Oracle JDK 1.7.0_17.Вы можете просмотреть источник своей версии Java в файле src.zip в каталоге установки Java.

2

Набор, возвращаемый keySet, поддерживается только базовой картой.

Согласно javadoc

Возвращает заданный вид ключей, содержащихся на этой карте. Набор поддерживается картой, поэтому изменения в карте отражаются в наборе и наоборот. Если карта изменена, когда выполняется итерация по множеству (за исключением операции удаления собственного итератора), результаты итерации не определены. Набор поддерживает удаление элементов, которое удаляет соответствующее сопоставление с карты через операции Iterator.remove, Set.remove, removeAll, keepAll и clear. Он не поддерживает операции add или addAll. Blockquote

HashMap хранит ключи в ведрах. Ключи, имеющие один и тот же хэш-код, входят в одно и то же ведро. При получении значения для ключа, если в ковке найдено более одного ключа, чем метод equals, используется для поиска правой клавиши и, следовательно, правильного значения.

2

Мне интересно, использует ли HashMap HashSet для хранения своих ключей.

Это не будет работать слишком хорошо, потому что Set только отслеживает ключи. У него нет способа сохранить сопоставление значений значений.

Противоположность (с использованием Карты для хранения элементов Set) возможна, однако, и этот подход используется:

HashSet реализуется с помощью HashMap (с фиктивным значением для всех ключей).

Набор ключей, возвращаемых HashMap#keySet, реализуется частным внутренним классом (HashMap.KeySet extends AbstractSet).

Вы можете изучить источник для обоих классов, например, на GrepCode: HashMap и HashSet.

Может ли кто-нибудь объяснить, как HashMap хранит свои ключи?

Он использует массив ведер. Каждое ведро имеет связанный список записей. Смотрите также

  • 1
    В JDK 8 корзина преобразуется в дерево, если связанный список становится слишком длинным.
  • 0
    См. Мой ответ на другой вопрос для описания политики перехода от списка к дереву.
1

Ответ: НЕТ.

HashMap.keySet() - это ПРОСМОТР ключей, содержащихся на этой карте.

Данные карты хранятся в таблице Entry[] HashMap.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню