map中的keySet和entrySet

HashMap的keySet和entrySet修改会影响原始Map,但通过源码分析发现,keySet.remove直接删除,而entrySet.remove需要传入Entry对象。非Entry对象传入entrySet.remove将不执行删除,通常使用map.remove或keySet.remove。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值