为什么 HashMap.keySet() 不返回空的 Set



keySet中的密钥来自哪里?类KeySetHashMap的内部类,它可以访问HashMap变量,但没有像Set<K>那样的直接变量,它只存储要引用的映射的键。

我只能找到一张Entry<K,V>[]表格。但它存储了密钥和值
当调用new KeySet()进行引用时,keySet()方法会执行某些操作吗?可能类似于:

for(Entry e : table) {
    keySet.put(e.getKey());
}

然后keySet存储的密钥,当添加或删除密钥值时,它也会添加或删除keySet中的密钥?

public Set<K> keySet() {
    Set<K> ks = keySet;
    return (ks != null ? ks : (keySet = new KeySet()));
}

源代码只显示了一个new KeySet(),但为什么它不是空的,而是有密钥?为了更清楚:

Map map = new HashMap();
map.put(1, 1);  //null
map.keySet();   //[1]
map.put(2, 2);  //[1,2]
map.remove(2);  //[1]

在每一行调试和断点,检查每一行并观察映射的keySet变量会显示上面的结果,对吗?

一旦调用了keySet((,put和remove将对keySet产生相同的效果,对吗?我观察了HashMap的put和remove方法。

对于"put((",如果在调用"table[bucketIndex]=new Entry<>(hash,key,value,e(;"后调用addEntry->createEntry->,keySet将添加密钥

for调用table[i]=next之后的"remove(("->removeEntryForKey->;keySet中的键被删除了,所以我认为表[]和keySet之间一定有关联,然后我问了这个问题。。。

keySet()返回由HashMap支持的内部Set实现。因此,例如,在该Set上调用contains(key)会调用在后台HashMap上的containsKey(key)

它不会创建一个独立的集合来保存原始HashMap的键(正如您在代码片段中所建议的(,因为这样的Set不会得到原始HashMap的支持,所以HashMap中的更改不会反映在Set中,反之亦然。

以下是Java 6的实现:

/**
 * Each of these fields are initialized to contain an instance of the
 * appropriate view the first time this view is requested.  The views are
 * stateless, so there's no reason to create more than one of each.
 */
transient volatile Set<K>        keySet = null;
public Set<K> keySet() {
    Set<K> ks = keySet;
    return (ks != null ? ks : (keySet = new KeySet()));
}
private final class KeySet extends AbstractSet<K> {
    public Iterator<K> iterator() {
        return newKeyIterator();
    }
    public int size() {
        return size;
    }
    public boolean contains(Object o) {
        return containsKey(o);
    }
    public boolean remove(Object o) {
        return HashMap.this.removeEntryForKey(o) != null;
    }
    public void clear() {
        HashMap.this.clear();
    }
}

您可以浏览java.util.HashMap的源代码来了解它是如何工作的。

keySet()函数实际上返回HashMap实例的一个成员变量,如下JDK源代码所示:

 public Set<K>  [More ...] keySet() {
     Set<K> ks = keySet;
     return (ks != null ? ks : (keySet = new KeySet()));
 }

keySetHashMap的成员变量,其中它是本地定义的类:

 private final class  [More ...] KeySet extends AbstractSet<K> {
     public Iterator<K>  [More ...] iterator() {
         return newKeyIterator();
     }
     public int  [More ...] size() {
         return size;
     }
     public boolean  [More ...] contains(Object o) {
         return containsKey(o);
     }
     public boolean  [More ...] remove(Object o) {
         return HashMap.this.removeEntryForKey(o) != null;
     }
     public void  [More ...] clear() {
         HashMap.this.clear();
     }
 }

因此,正如您所看到的,它只是为HashMap中保存的相同数据定义了另一个"视图"。不会复制任何内容,因此可以保证keySet视图和原始贴图视图之间的一致性。

好的,我明白原因了。该方法确实返回了一个空的KeySet。但当它中断时,eclipse将调用方法AbstractCollection.toString((…然后调用KeySet.iterator((方法。

最新更新