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

前端 未结 3 805
自闭症患者
自闭症患者 2021-02-20 07:22

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

public Collection values() {
    Collection vs = values;
    return (vs !=         


        
相关标签:
3条回答
  • 2021-02-20 07:49

    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]"
    
    0 讨论(0)
  • 2021-02-20 07:50

    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 Sets returned by keySet and entrySet.

    0 讨论(0)
  • 2021-02-20 08:03
    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 valuesalways 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.

    0 讨论(0)
提交回复
热议问题