Java 为什么';t LinkedHashMap keyset()返回LinkedHashSet vs Set?
我读过java文档,也读过这篇文章,LinkedHashMaps的Java 为什么';t LinkedHashMap keyset()返回LinkedHashSet vs Set?,java,collections,linkedhashmap,linkedhashset,Java,Collections,Linkedhashmap,Linkedhashset,我读过java文档,也读过这篇文章,LinkedHashMaps的keyset()维护了秩序。 我的问题是,如果它保证了顺序,那么为什么LinkedHashMap的源代码不返回一个Set类型的对象来保证顺序,比如LinkedHashSet 我可能想到的一个原因是LinkedHashSet使用了一个映射,这将增加内存分配(取决于AbstractSet的实现方式)。这是否也是因为它证明了密钥集的未来实现 就像这篇文章中的回答: 返回一个列表符合编程到最合适的位置 接口 返回集合会导致用户产生歧义,
keyset()
维护了秩序。
我的问题是,如果它保证了顺序,那么为什么LinkedHashMap
的源代码不返回一个Set
类型的对象来保证顺序,比如LinkedHashSet
我可能想到的一个原因是LinkedHashSet使用了一个映射,这将增加内存分配(取决于AbstractSet的实现方式)。这是否也是因为它证明了密钥集的未来实现
就像这篇文章中的回答:
返回一个列表符合编程到最合适的位置
接口
返回集合会导致用户产生歧义,例如
返回的集合可以是:集合、列表或队列
因此,如果不阅读keyset()
的文档,这不是很含糊吗
keyset()
源代码:
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();
}
}
公共设置键集(){
设置ks=键集;
返回(ks!=null?ks:(keySet=newkeyset());
}
私有最终类键集扩展了抽象集{
公共迭代器迭代器(){
返回newKeyIterator();
}
公共整数大小(){
返回大小;
}
公共布尔包含(对象o){
返回集装箱箱(o);
}
公共布尔删除(对象o){
返回HashMap.this.RemoveEntryWorkey(o)!=null;
}
公共空间清除(){
HashMap.this.clear();
}
}
它返回由映射
界面定义的集合
。Set
只是不包含重复元素的集合。另一方面,列表
是一个有序的集合(也称为序列)。列表
界面没有指定元素是唯一的
尽管如此,LinkedKeyMap
实现实际上返回了底层的键集,它是一个LinkedKeySet
,而LinkedKeySet
的forEach()
方法是保序的,即:
//from the source code for the LinkedHashMap:
public Set<K> keySet() {
Set<K> ks;
return (ks = keySet) == null ? (keySet = new LinkedKeySet()) : ks;
}
//来自LinkedHashMap的源代码:
公共集密钥集(){
设置ks;
return(ks=keySet)==null?(keySet=newlinkedkeyset()):ks;
}
因此,在本例中,元素都是唯一且有序的。为什么LinkedHashMap
的源代码不返回类型为Set
的对象
,以保证像LinkedHashSet
那样的顺序
因为LinkedHashSet
是一个具体的类,它自己的实现维护自己的数据,并且该方法必须返回Map
的视图,所以它不能只将关键数据复制到LinkedHashSet
。见javadoc:
返回此映射中包含的键的Set
视图。集合由映射支持,因此映射的更改将反映在集合中,反之亦然
如果它保证了顺序,那么为什么LinkedHashMap的源代码不返回一个像LinkedHashSet一样保证顺序的Set类型的对象呢
键集的声明类型是从Map.keySet()
声明的类型中提取的<在将协变返回类型添加到Java语言之前,已将code>LinkedHashMap添加到标准库中。当时,除了使用typeSet
之外,别无选择
在任何情况下,键集必须与基础映射具有相同的顺序并不意味着它必须是LinkedHashSet
,事实上它不能是,因为它不能支持元素添加。它的类是classLinkedHashMap
的私有嵌套类。该类和Set
之间没有比Set
作为返回类型更有用的公共类型
事实上,我认为要定义一个是不容易的。什么是它区别于任何其他集合的基本特征?您不能只说“迭代顺序”,而不指定迭代顺序实例将具有什么,并且该顺序取决于从中获取集合的LinkedHashMap
实例。换句话说,迭代顺序是实例特征,而不是类特征。因此,表示作为LinkedHashMap
的键集性质的声明类型除了set
提供的信息外,几乎不提供任何实际用途的信息
无论如何,我不认为你引用的关于返回列表
与返回集合
的摘录很有说服力。事实上,对象特定类的模糊性本质上不是一个问题。在集合
与列表
的示例中,如果type集合
很好地捕获了方法的返回类型要求,因此没有特别的原因需要列表
的特征,那么集合
是返回类型的一个好选择。如果需求也可以通过集合
来满足,这尤其好,因为这样API就不会在两个同样好的备选方案之间做出本质上的任意选择
有一个学派认为,方法的参数类型应该尽可能一般,返回类型应该尽可能具体。我认为这个想法很有价值,但它更像是一个指导方针而不是一个规则,而且对于“尽可能具体”的具体程度有很大的解释余地。尽管你的第二部分是正确的,第一个不一定是正确的,因为Map接口指定Set并不意味着它不能用LinkedKeySet重写。我的重点是强调
LinkedKeySet
提供了对其元素的排序。我不想暗示集合
也不能实现列表
接口@A.