我想知道HashMap是否使用HashSet来存储其密钥。我猜它会这样,因为HashMap会与HashSet对应,而TreeMap会与TreeSet对应。
我查看了HashMap类的源代码,该方法返回一个由某种迭代器实现的AbstractSet。
另外......我写的时候
HashMap map = new HashMap();
if(map.keySet() instanceof HashSet){
System.out.println("true");
}
以上if语句永远不会运行。现在我不确定
有人可以解释HashMap如何存储其密钥吗?
答案 0 :(得分:2)
我想知道HashMap是否使用HashSet存储其密钥。
这不会太好用,因为Set只跟踪键。它无法存储关联的值映射。
相反(使用Map来存储Set元素)是可能的,并且正在使用这种方法:
HashSet
是使用HashMap
(所有键的虚拟值)实现的。
HashMap#keySet
返回的密钥集由私有内部类(HashMap.KeySet extends AbstractSet
)实现。
您可以研究这两个类的来源,例如GrepCode:HashMap和HashSet。
有人可以解释HashMap如何存储其密钥吗?
它使用一系列桶。每个存储桶都有一个链接的条目列表。另见
答案 1 :(得分:2)
keySet返回的集仅由基础地图支持。
根据javadoc
返回此地图中包含的键的Set视图。该集由地图支持,因此对地图的更改将反映在集中,反之亦然。如果在对集合进行迭代时修改了映射(除了通过迭代器自己的删除操作),迭代的结果是未定义的。该集支持元素删除,它通过Iterator.remove,Set.remove,removeAll,retainAll和clear操作从地图中删除相应的映射。它不支持add或addAll操作。 块引用
HashMap将密钥存储到存储桶中。具有相同哈希码的密钥进入同一个桶。如果在桶中找到多个键,则检索键的值时,使用equals方法来查找正确的键,从而找到正确的值。
答案 2 :(得分:2)
你实际上问了两个不同的问题:
HashMap
是否使用HashSet
存储密钥?HashMap.keySet()
会返回HashSet
吗?这两个问题的答案都是否定的,并且出于同样的原因,但没有技术上的理由阻止1.或2.无效。
HashSet
实际上是HashMap
的包装器; HashSet
具有以下成员变量:
private transient HashMap<E,Object> map;
当对象添加到集合时,它会将PRESENT
sentinel值填充为地图的值。
现在HashMap
将数据存储在包含Key,Value对的Entry
个对象数组中:
transient Entry<K,V>[] table;
它的keySet()
方法返回内部类KeySet
的一个实例:
public Set<K> keySet() {
Set<K> ks = keySet;
return (ks != null ? ks : (keySet = new KeySet()));
}
private final class KeySet extends AbstractSet<K> {
// minimal Set implementation to access the keys of the map
}
由于KeySet
是一个私有的内部类,因此您应该关注它只是一个任意的Set
实现。
就像我说的那样, 没有理由这样做。您绝对可以实现内部使用Map
的{{1}}类,然后让HashSet
从Map
返回HashSet
。然而,这将是低效且难以编码的;现有的实现比天真的.keySet()
/ Map
实现更强大,更有效。
从Oracle JDK 1.7.0_17获取的代码片段。您可以在Java安装目录的Set
文件中查看Java版本的源代码。
答案 3 :(得分:1)
答案是:否。
HashMap.keySet()
是此地图中包含的键的 VIEW 。
地图数据存储在Entry[]
的{{1}}表中。