import java.util.HashMap;output: original map:{1=aa, 2=bb, 3=cc}
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);
}
}
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) {也就是说这个keySet调用的是HashMap本生的remove方法,故而keySet的修改也会影响到map的修改。(验证了API中所说的)
return HashMap.this.removeEntryForKey(o) != null;
}
在来查看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