简体   繁体   中英

How do HashMap.values() and HashMap.keySet() return values and keys?

The source code of HashMap.values() is shown as follows

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

As you can see, when the values() method first called, it just returns a Values object. The Values object is a subclass of AbstractCollection with no constructor, and of course contains no element. But when I called the method, it returned a collection rapidly

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

That's so weird. Not only values() , but also keySet() and entrySet() method return such empty objects. So, here is my question, when and how do these methods return objects with elements we need?

It's a misconception that the Values class is "of course empty". Just because there is no method called on it and its constructor doesn't have any arguments doesn't mean that the collection is empty.

The Values class is an "inner class" (a non-static nested class ) of HashMap , which means that it has an implicit reference to the HashMap object that created it. It can therefore access all elements of the HashMap , either explicitly by using the HashMap.this reference or by just accessing the members directly. Since it is an inner class, it is even allowed to access the HashMap 's private members.

You can see that for example in the Values class' implementation of the size method:

public int size() {
    return size;
}

The Values class doesn't have a size member, so that size refers to the HashMap 's size. It's equivalent to:

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

EDIT: Note that this also means that the collection you receive is not a copy, but still refers to the original HashMap contents and therefore changes when you update the 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]"

The Values class implements a Collection that is backed by the HashMap . As mastov commented, Values is an inner class of HashMap , which gives it access to the members of the enclosing HashMap instance it is associated with. Therefore it's not empty. Its size is the size of the HashMap , and when you iterate over it, you are iterating over the Entries of the HashMap .

When you call System.out.println(values); , you are calling the toString method of AbstractCollection , which uses an Iterator to iterate over the values and get their String representation. The Iterator actually iterates over the Entries of the HashMap and returns their values.

The same goes for the Set s returned by keySet and entrySet .

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

These two line answer your question.

values is a internal collection (Inherited from AbstractMap ). If it is not null then it will be returned.
If it is null then it will be initialized and the new one will returned.

Now I guess, the main point of your question is
when and how do these methods return objects with elements we need?

Technically values always return this initialized Object. Then how we get our entry values from these object.?
Lets go a little deep:

values() actually return an object of class Values which is an Inner class of HashMap and extends AbstractCollection

private final class Values extends AbstractCollection<V> 

As you have looked into the source code. Then you will find inside the Values class

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

this newValueIterator() does the trick.
If you go more deeper you will find newValueIterator() returns object of ValueIterator which is a subclass of HashIterator HashIterator implements basic functionality for iteration, which actually itterate over the table maintained by the HashMap .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM