为什么map.vaules上的迭代器可以用来删除HashMap#Entry?

cai*_*sil 5 java iterator hashmap

我正在尝试删除值为的所有条目null.代码是:

Map<String, String> map = new HashMap<>();
map.put("one", null);
map.put("two", null);
map.put("three", "THREE");

Iterator iterator = map.values().iterator();
while (iterator.hasNext())
{
    if (iterator.next() == null) {
        iterator.remove();
    }
}

for (Map.Entry<String, String> e : map.entrySet()) {
    System.out.println(e.getKey() + ":" + e.getValue());
}
Run Code Online (Sandbox Code Playgroud)

我的问题是iterator绑定map.values,为什么它可以删除整个条目?

Zab*_*uza 8

这是可能的,因为Map#values返回地图支持的值的视图.

来自官方Java-Doc of Map#值:

返回此映射中包含的值的Collection视图.该集合由地图支持,因此对地图的更改将反映在集合中,反之亦然.[...]该集合支持元素删除,它通过Iterator.remove,Collection.remove,removeAll,retainAll和clear操作从地图中删除相应的映射.它不支持add或addAll操作.


请注意,AbstractMap大多数地图实现扩展的类都有一个额外的字段transient volatile Collection<V> values,这正是您将在那里获得的.如您所见,集合在内部由Map使用,因此对它的更改也会反映在Map本身上.另请参见:AbstractMap的源代码


如果您想详细介绍,请查看AbstractMap#values源代码中的方法.在那里,他们创建 -collection作为在原始地图上运行的包装器.例如,它的next方法迭代Entry<K, V>Map 的条目,但只返回它们的值,Entry#getValue依此类推.
此外remove,正如您所见,该方法将被传递给迭代器Entry<K, V>,因此最终将在原始映射上执行remove.