Почему HashMap.keySet() не возвращает пустой Set

Где ключи keySet родом из? Класс KeySet это внутренний класс HashMapимеет доступ к HashMap переменные, но нет прямой переменной, как Set<K> который хранит только ключи карты для ссылки.

Я могу только найти Entry<K,V>[] Таблица. Но он сохранил ключ и значение.
Ли keySet() метод сделать что-то, когда new KeySet() называется сделать ссылку? Может быть как:

for(Entry e : table) {
    keySet.put(e.getKey());
}

затем ключ устанавливает хранимые ключи, а когда добавляет или удаляет ключ-значение, он также добавляет или удаляет ключи в keySet тот же самый?

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

Исходный код показывает только new KeySet(), но почему он не пустой, но имеет ключи? Чтобы было понятнее:

Map map = new HashMap();
map.put(1, 1);  //null
map.keySet();   //[1]
map.put(2, 2);  //[1,2]
map.remove(2);  //[1]

отладка и точка останова в каждой строке, проверка каждой строки и наблюдение, что переменная keySet карты покажет результат выше, верно?

После вызова keySet() операции put и remove будут иметь тот же эффект для набора ключей, верно? Я смотрел на метод положить и удалить HashMap.

для "put()", если вызывается addEntry -> createEntry -> после вызова "table[bucketIndex] = new Entry<>(hash, key, value, e);" набор ключей добавит ключ,

для "remove()" ->removeEntryForKey -> после вызова таблицы [i] = next; ключ в keySet был удален, поэтому я думаю, что между таблицей [] и keySet должна быть какая-то связь, а затем я задал этот вопрос...

3 ответа

keySet() возвращает внутренний Set реализация при поддержке HashMap, Так, например, позвонив contains(key) на этот набор звонков containsKey(key) на основе HashMap,

Он не создает независимый набор, содержащий ключи оригинала HashMap (как вы предложили в своем фрагменте кода), так как такой Set не будет подкреплено оригиналом HashMapтак что изменения в HashMap не будет отражено в Set и наоборот.

Вот реализация Java 6:

/**
 * Each of these fields are initialized to contain an instance of the
 * appropriate view the first time this view is requested.  The views are
 * stateless, so there's no reason to create more than one of each.
 */
transient volatile Set<K>        keySet = null;

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

private final class KeySet extends AbstractSet<K> {
    public Iterator<K> iterator() {
        return newKeyIterator();
    }
    public int size() {
        return size;
    }
    public boolean contains(Object o) {
        return containsKey(o);
    }
    public boolean remove(Object o) {
        return HashMap.this.removeEntryForKey(o) != null;
    }
    public void clear() {
        HashMap.this.clear();
    }
}

Хорошо, я получаю причину. Метод действительно возвращает пустой KeySet.but, когда прерывается на нем. Затмение вызовет метод AbstractCollection.toString()... затем вызван метод KeySet.iterator().

Вы можете просмотреть исходный код java.util.HashMap чтобы понять, как это работает.

keySet() Функция фактически возвращает переменную-член HashMap экземпляр как следующий исходный код JDK получил:

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

Тогда keySet является переменной-членом HashMap где его локально определенный класс:

 private final class  [More ...] KeySet extends AbstractSet<K> {
     public Iterator<K>  [More ...] iterator() {
         return newKeyIterator();
     }

     public int  [More ...] size() {
         return size;
     }

     public boolean  [More ...] contains(Object o) {
         return containsKey(o);
     }

     public boolean  [More ...] remove(Object o) {
         return HashMap.this.removeEntryForKey(o) != null;
     }

     public void  [More ...] clear() {
         HashMap.this.clear();
     }

 }

Итак, как вы можете видеть, он просто определяет другое "представление" тех же данных, хранящихся в HashMap, Ничто не дублируется, поэтому гарантируется согласованность между представлением keySet и исходным представлением карты.

Другие вопросы по тегам