map中的keySet和entrySet

时间:2022-06-19 15:48:12
import java.util.HashMap;
import java.util.Map;

public class KeySetTest {
public static void main(String[] args) {
Map<Integer,String> map = new HashMap<Integer, String>();
map.put(1, "aa");
map.put(2, "bb");
map.put(3, "cc");

System.out.println(map);

map.entrySet().remove(1);
System.out.println(map);
System.out.println("==========================");
map.keySet().remove(1);
System.out.println(map);

}
}
output: original map:{1=aa, 2=bb, 3=cc}
              after entrySet modify:{1=aa, 2=bb, 3=cc}

              after keySet modify:{2=bb, 3=cc}

查了API,对两个方法的描述分别是:

keySet

Set<K> keySet()
Returns a Set view of the keys contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa.


entrySet

Set<Map.Entry<K,V>> entrySet()
Returns a Set view of the mappings contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa.


也就是说对keySet视图跟对entrySet视图的修改 都会影响到原来的map。  

但是上面的代码的结果却是只有keySet的修改影响了map   这是为什么???

====================================================================================


知道答案了。

查看源码 发现在HashMap中的KeySet的remove方法是这样的

public boolean remove(Object o) {
return HashMap.this.removeEntryForKey(o) != null;
}
也就是说这个keySet调用的是HashMap本生的remove方法,故而keySet的修改也会影响到map的修改。(验证了API中所说的)

在来查看removeEntryForKey方法

    final Entry<K,V> removeEntryForKey(Object key) {
int hash = (key == null) ? 0 : hash(key.hashCode());
int i = indexFor(hash, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> e = prev;

while (e != null) {
Entry<K,V> next = e.next;
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
modCount++;
size--;
if (prev == e)
table[i] = next;
else
prev.next = next;
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
}

return e;
}

大概流程是 先算出参数key的hashCode,然后找到Entry里对应这个key的元素e,然后调用e.recordRemoval(this)方法来删除这个元素。


再来看看entrySet的remove方法吧:

public boolean remove(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
return ConcurrentHashMap.this.remove(e.getKey(), e.getValue());
}

它首先会判断传入的参数o是不是一个entry对象,如果不是,直接返回false。  显然最前面的例子中,1不是一个entry对象,所以就直接返回false了,后面的remove操作就没有执行到了。

要是一定想用entrySet.remove()方法来删除的话,可以这样写map.entrySet().remove(map.entrySet().iterator().next()); 但这样显然没有意思。

所以一般来说不会用entrySet的remove方法来删除map中一条entry, 而是用map.remove 或者keySet.remove