Мне интересно, использует ли HashMap HashSet для хранения своих ключей. Я бы предположил, что это так, потому что HashMap будет соответствовать HashSet, а TreeMap будет соответствовать TreeSet.
Я посмотрел исходный код для класса HashMap, и этот метод возвращает AbstractSet, реализованный каким-то Iterator.
Кроме того... когда я пишу
HashMap map = new HashMap();
if(map.keySet() instanceof HashSet){
System.out.println("true");
}
Вышеприведенный оператор if никогда не запускается. Теперь я не уверен
Может ли кто-нибудь объяснить, как HashMap хранит свои ключи?
Вы задаете два вопроса:
HashMap
HashSet
для хранения своих ключей?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.
Набор, возвращаемый keySet, поддерживается только базовой картой.
Согласно javadoc
Возвращает заданный вид ключей, содержащихся на этой карте. Набор поддерживается картой, поэтому изменения в карте отражаются в наборе и наоборот. Если карта изменена, когда выполняется итерация по множеству (за исключением операции удаления собственного итератора), результаты итерации не определены. Набор поддерживает удаление элементов, которое удаляет соответствующее сопоставление с карты через операции Iterator.remove, Set.remove, removeAll, keepAll и clear. Он не поддерживает операции add или addAll. Blockquote
HashMap хранит ключи в ведрах. Ключи, имеющие один и тот же хэш-код, входят в одно и то же ведро. При получении значения для ключа, если в ковке найдено более одного ключа, чем метод equals, используется для поиска правой клавиши и, следовательно, правильного значения.
Мне интересно, использует ли HashMap HashSet для хранения своих ключей.
Это не будет работать слишком хорошо, потому что Set только отслеживает ключи. У него нет способа сохранить сопоставление значений значений.
Противоположность (с использованием Карты для хранения элементов Set) возможна, однако, и этот подход используется:
HashSet
реализуется с помощью HashMap
(с фиктивным значением для всех ключей).
Набор ключей, возвращаемых HashMap#keySet
, реализуется частным внутренним классом (HashMap.KeySet extends AbstractSet
).
Вы можете изучить источник для обоих классов, например, на GrepCode: HashMap и HashSet.
Может ли кто-нибудь объяснить, как HashMap хранит свои ключи?
Он использует массив ведер. Каждое ведро имеет связанный список записей. Смотрите также
Ответ: НЕТ.
HashMap.keySet()
- это ПРОСМОТР ключей, содержащихся на этой карте.
Данные карты хранятся в таблице Entry[]
HashMap
.
Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
, см.Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
член в HashMap - используется массив, а не HashSet.)