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

时间:2015-08-04 08:03:56

标签: java hashmap keyset

keySet中的密钥来自哪里? 类KeySetHashMap的内部类,它可以访问HashMap个变量,但没有像Set<K>这样的直接变量,它只存储地图的键参考。

我只能找到Entry<K,V>[]表。但它存储了关键和价值 keySet()方法在调用new 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()”,如果调用addEntry - &gt; createEntry - &gt;在调用“table [bucketIndex] = new Entry&lt;&gt;(hash,key,value,e)之后;” keySet将添加密钥

代表“remove()” - &gt; removeEntryForKey - &gt;在调用table [i] = next之后; keySet中的键被删除了,所以我认为table []和keySet之间必定有一些关联,然后我问了这个问题......

3 个答案:

答案 0 :(得分:1)

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

它不会创建一个独立的Set,其中包含原始HashMap的密钥(正如您在代码段中所建议的那样),因为这样的Set不会被原始HashMap支持1}},因此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();
    }
}

答案 1 :(得分:0)

您可以浏览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视图与原始地图视图之间的一致性。

答案 2 :(得分:0)

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