提问者:小点点

hashmap中的entrySet如何创建和修改?


/**
 * Holds cached entrySet(). Note that AbstractMap fields are used
 * for keySet() and values().
 */
transient Set<Map.Entry<K,V>> entrySet;

我在javaHashmap中发现了一件奇怪的事情。我在hashmap源代码和AbstractMap代码中找不到创建和操作entrySet实例的代码。但是当我把key-value放在hashmap中时,entrySet得到了新的值。这很奇怪。

所以我的问题是:

entrySet如何获取新值,何时获取其实例?

为了更清楚,我在IDE中添加了调试代码,发现在我第一次调用这个集合之前,它已经不是空的,并且充满了元素。


共3个答案

匿名用户

这个entrySet字段是在调用entrySet()方法时设置的。请参阅OpenJDK 8中entrySet()的源代码:

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

还要检查链接源代码中方法正下方的内部EntrySet类。

匿名用户

entrySet如何获取新值,何时获取其实例?

entrySet的实例是在第一次调用Map. entrySet()时创建的。

我们可以在HashMap的源代码中看到:

 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();

        }

        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类只是作用于内部HashMap的一组方法。因此,EntrySet不包含任何信息,它只是对HashMap的数据的视图。

匿名用户

Map. entrySet只会让您将Map视为Set

Java内部类有两个(或更多)this(假设它们不是静态上下文中的本地类)。在Python,按照惯例,self用于this。(我Python没做那么多。)所以内部类的任何方法都会隐藏外部的self。你必须使用不同的名称,当然每次使用它们时都要显式。在Java,如果你不显式,它会选择合适的this(在角落情况下可能会很奇怪)。