繁体   English   中英

entrySet()如何在HashMap内部工作?

[英]How entrySet() works internally in HashMap?

我试图了解HashMap中的entrySet()函数,但不确定创建新的EntrySet()时它如何工作以及从何处填充值。

public Set<Map.Entry<K,V>> entrySet() {
    return entrySet0();
}

private Set<Map.Entry<K,V>> entrySet0() {
    Set<Map.Entry<K,V>> es = entrySet;
    return es != null ? es : (entrySet = new EntrySet());
}

以下是jdk8中entrySet()的源代码:

public Set<Map.Entry<K,V>> entrySet() {
    Set<Map.Entry<K,V>> es;
    return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}

final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
    public final int size()                 { return size; }
    public final void clear()               { HashMap.this.clear(); }
    public final Iterator<Map.Entry<K,V>> iterator() {
        return new EntryIterator();//get the iterator
    }
    public final boolean contains(Object o) {
        if (!(o instanceof Map.Entry))
            return false;
        Map.Entry<?,?> e = (Map.Entry<?,?>) o;
        Object key = e.getKey();
        Node<K,V> candidate = getNode(hash(key), key);
        return candidate != null && candidate.equals(e);
    }
    public final boolean remove(Object o) {
        if (o instanceof Map.Entry) {
            Map.Entry<?,?> e = (Map.Entry<?,?>) o;
            Object key = e.getKey();
            Object value = e.getValue();
            return removeNode(hash(key), key, value, true, true) != null;
        }
        return false;
    }
    public final Spliterator<Map.Entry<K,V>> spliterator() {
        return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
    }
    public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
        Node<K,V>[] tab;
        if (action == null)
            throw new NullPointerException();
        if (size > 0 && (tab = table) != null) {
            int mc = modCount;
            for (int i = 0; i < tab.length; ++i) {
                for (Node<K,V> e = tab[i]; e != null; e = e.next)
                    action.accept(e);
            }
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }
}

第一:当我们使用entrySet()方法时,它返回新的EntrySet(),它是EntrySet的一个实例。 此类具有iterator()方法,可用于...循环。 然后iterator()方法返回一个iterator(class:EntryIterator)

第二:我们阅读了最终类EntryIterator的源代码:

final class EntryIterator extends HashIterator implements Iterator<Map.Entry<K,V>> {
    public final Map.Entry<K,V> next() { return nextNode(); }
}

从代码中,我们可以看到它实现了next()方法。 然后返回nextNode();

第三:我们阅读nextNode方法的源代码(在HashIterator类中):

abstract class HashIterator {
    Node<K,V> next;        // next entry to return
    Node<K,V> current;     // current entry
    int expectedModCount;  // for fast-fail
    int index;             // current slot

    HashIterator() { //when new EntryIterator, this will load data first.
        expectedModCount = modCount;
        Node<K,V>[] t = table;
        current = next = null;
        index = 0;
        if (t != null && size > 0) { // advance to first entry
            do {} while (index < t.length && (next = t[index++]) == null);
        }
    }

    public final boolean hasNext() {
        return next != null;
    }

    final Node<K,V> nextNode() {
        Node<K,V>[] t;
        Node<K,V> e = next;
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        if (e == null)
            throw new NoSuchElementException();
        if ((next = (current = e).next) == null && (t = table) != null) {
            do {} while (index < t.length && (next = t[index++]) == null);
        }
        return e;
    }

    public final void remove() {
        Node<K,V> p = current;
        if (p == null)
            throw new IllegalStateException();
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        current = null;
        K key = p.key;
        removeNode(hash(key), key, null, false, false);
        expectedModCount = modCount;
    }
}

根据新对象的顺序。 它将根据以下顺序使用构造函数>对象--->超类--->最后一个将是自身

像这样的jsut:新的HashIterator()然后是新的EntryIterator()

当使用新的EntryIterator()时,它将在其自身之前使用HashIterator的构造方法。 我们可以看到当我们使用HashIterator的构造方法时,它将加载HashMap的数据

然后nextNode()方法从这些数据中获取数据。 因此,我们可以使用...循环来获取HashMap对象的所有节点。

资源

HashMap内部有一个内部类

private final class EntrySet extends AbstractSet...

这是HashMapentrySet()方法返回的结果。

当您在EntrySet类中调用一个方法检查其内容时,它将在HashMap查找信息。 如果您在EntrySet添加或删除项目,它将影响HashMap (反之亦然)。 本质上,这只是查看同一容器的另一种方法。 它没有自己的Map内容副本。

在创建新的EntrySet()时在何处填充值

您在HashMap.java中查看的EntrySet不是新集合,而是HashMap本身支持的功能包装(请阅读javadoc)。

EntrySet上的操作委托给HashMap本身。

因此,EntrySet实际上不保存任何内容。 EntrySet不需要填充。

从来源:

private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
    public Iterator<Map.Entry<K,V>> iterator() {
        return newEntryIterator();
    }
    public boolean contains(Object o) {
        if (!(o instanceof Map.Entry))
            return false;
        Map.Entry<K,V> e = (Map.Entry<K,V>) o;
        Entry<K,V> candidate = getEntry(e.getKey());
        return candidate != null && candidate.equals(e);
    }
    public boolean remove(Object o) {
        return removeMapping(o) != null;
    }
    public int size() {
        return size;
    }
    public void clear() {
        HashMap.this.clear();
    }
}

如您所见,该类不是集合,而是实际Map的视图

entrySet()方法用于获取此映射中包含的映射的Set视图。

因此,这将返回给您存储在Map中的值的集合表示形式,但这与Map链接,因此在Map迭代期间,如果您更改了任何内容,它将反映在Set中。

另一方面,集合支持元素删除,该元素通过Iterator.remove,Set.remove,removeAll,retainAll和clear操作从映射中删除相应的映射。 它不支持add或addAll操作。

查看此示例以获取有关其工作方式的详细信息。

http://www.tutorialspoint.com/java/util/hashmap_entryset.htm

条目集不需要填充值,如果您调用iterator(),它将调用newEntryIterator(),

private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
    public Iterator<Map.Entry<K,V>> iterator() {
        return newEntryIterator();
    }
}
Iterator<Map.Entry<K,V>> newEntryIterator()   {
    return new EntryIterator();
}
private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
    public Map.Entry<K,V> next() {
        return nextEntry();
    }
}
final Entry<K,V> nextEntry() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        Entry<K,V> e = next;
        if (e == null)
            throw new NoSuchElementException();

        if ((next = e.next) == null) {
            Entry[] t = table;
            while (index < t.length && (next = t[index++]) == null)
                ;
        }
        current = e;
        return e;
    }

您可以考虑将<键,值>放入集合中的方式。 遍历地图很方便。

for (Map.Entry me: map.entrySet()) {
    System.out.println("key" + me.getKey() + " value" + me.getValue());
}

而不是使用键在地图上查找值

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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