Подтвердить что ты не робот

Как HashMap.values ​​() и HashMap.keySet() возвращают значения и ключи?

Исходный код HashMap.values() показан следующим образом

public Collection<V> values() {
    Collection<V> vs = values;
    return (vs != null ? vs : (values = new Values()));
}

Как вы можете видеть, при первом вызове метода values() он просто возвращает объект Values. Объект Values является подклассом AbstractCollection без конструктора и, конечно, не содержит элемента. Но когда я вызвал метод, он быстро возвращал коллекцию

Collection<String> values = map.values();
System.out.println(values);

Это так странно. Не только values(), но и методы keySet() и entrySet() возвращают такие пустые объекты. Итак, вот мой вопрос, когда и как эти методы возвращают объекты с элементами, которые нам нужны?

4b9b3361

Ответ 1

Это неправильное представление о том, что класс Values "конечно пуст". Просто потому, что в нем нет метода, и его конструктор не имеет никаких аргументов, это не значит, что коллекция пуста.

Класс Values - это "внутренний класс" (нестатический вложенный класс) HashMap, что означает, что он имеет неявную ссылку на объект HashMap, который его создал. Поэтому он может обращаться ко всем элементам HashMap, либо явно, используя ссылку HashMap.this, либо просто обращаясь к членам напрямую. Поскольку это внутренний класс, ему даже разрешен доступ к частным членам HashMap.

Вы можете увидеть это, например, в реализации метода Values класса Values:

public int size() {
    return size;
}

Класс Values не имеет члена size, поэтому size относится к размеру HashMap. Это эквивалентно:

public int size() {
    return HashMap.this.size;
}

РЕДАКТИРОВАТЬ: Обратите внимание, что это также означает, что получаемая вами коллекция не является копией, но все же относится к исходному содержимому HashMap и поэтому изменяется при обновлении HashMap:

    // Getting the entry set (not a copy!)
    Set<Entry<String, String>> entries = map.entrySet();

    // Add elements to the map afterwards
    map.put("abc", "def");

    // Check out the entries in the collection
    // (magically containing the elements added after getting the collection)
    System.out.println(entries); // "[abc=def]"

Ответ 2

Класс Values реализует Collection, который поддерживается HashMap. Как отметил мастов, Values является внутренним классом HashMap, который дает ему доступ к членам экземпляра HashMap, с которым он связан. Поэтому он не пуст. Его размер - это размер HashMap, и когда вы перебираете его, вы повторяете записи HashMap.

Когда вы вызываете System.out.println(values);, вы вызываете метод toString AbstractCollection, который использует Iterator для итерации по значениям и получения их представления String. Iterator фактически выполняет итерации над записями HashMap и возвращает их значения.

То же самое относится к Set, возвращаемому keySet и entrySet.

Ответ 3

Collection<V> vs = values;
return (vs != null ? vs : (values = new Values()));

Эти две строки отвечают на ваш вопрос.

values является внутренней коллекцией (Унаследовано от AbstractMap). Если это не null, то оно будет возвращено.
Если оно null, то оно будет инициализировано и будет возвращено новое.

Теперь, я думаю, основной вопрос вашего вопроса: , когда и как эти методы возвращают объекты с элементами, которые нам нужны?

Технически values всегда возвращает этот инициализированный объект. Затем, как мы получаем наши значения ввода из этого объекта.?
Давайте немного углубимся:

values ​​() фактически возвращают объект класса values, который является классом Inner HashMap и расширяет AbstractCollection

private final class Values extends AbstractCollection<V> 

Как вы изучили исходный код. Затем вы найдете внутри класса values

public Iterator<V> iterator() {
        return newValueIterator();
    }

этот newValueIterator() делает трюк.
Если вы пойдете глубже, вы обнаружите, что newValueIterator() возвращает объект ValueIterator, который является подклассом HashIterator HashIterator реализует основные функциональные возможности для итерации, которые на самом деле повторяются над table, поддерживаемыми HashMap.