Java 为什么';t LinkedHashMap keyset()返回LinkedHashSet vs Set?

Java 为什么';t LinkedHashMap keyset()返回LinkedHashSet vs Set?,java,collections,linkedhashmap,linkedhashset,Java,Collections,Linkedhashmap,Linkedhashset,我读过java文档,也读过这篇文章,LinkedHashMaps的keyset()维护了秩序。 我的问题是,如果它保证了顺序,那么为什么LinkedHashMap的源代码不返回一个Set类型的对象来保证顺序,比如LinkedHashSet 我可能想到的一个原因是LinkedHashSet使用了一个映射,这将增加内存分配(取决于AbstractSet的实现方式)。这是否也是因为它证明了密钥集的未来实现 就像这篇文章中的回答: 返回一个列表符合编程到最合适的位置 接口 返回集合会导致用户产生歧义,

我读过java文档,也读过这篇文章,LinkedHashMaps的
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添加到标准库中。当时,除了使用type
Set
之外,别无选择

在任何情况下,键集必须与基础映射具有相同的顺序并不意味着它必须是
LinkedHashSet
,事实上它不能是,因为它不能支持元素添加。它的类是class
LinkedHashMap
的私有嵌套类。该类和
Set
之间没有比
Set
作为返回类型更有用的公共类型

事实上,我认为要定义一个是不容易的。什么是它区别于任何其他集合的基本特征?您不能只说“迭代顺序”,而不指定迭代顺序实例将具有什么,并且该顺序取决于从中获取集合的
LinkedHashMap
实例。换句话说,迭代顺序是实例特征,而不是类特征。因此,表示作为
LinkedHashMap
的键集性质的声明类型除了
set
提供的信息外,几乎不提供任何实际用途的信息

无论如何,我不认为你引用的关于返回
列表
与返回
集合
的摘录很有说服力。事实上,对象特定类的模糊性本质上不是一个问题。在
集合
列表
的示例中,如果type
集合
很好地捕获了方法的返回类型要求,因此没有特别的原因需要
列表
的特征,那么
集合
是返回类型的一个好选择。如果需求也可以通过
集合
来满足,这尤其好,因为这样API就不会在两个同样好的备选方案之间做出本质上的任意选择


有一个学派认为,方法的参数类型应该尽可能一般,返回类型应该尽可能具体。我认为这个想法很有价值,但它更像是一个指导方针而不是一个规则,而且对于“尽可能具体”的具体程度有很大的解释余地。

尽管你的第二部分是正确的,第一个不一定是正确的,因为Map接口指定Set并不意味着它不能用LinkedKeySet重写。我的重点是强调
LinkedKeySet
提供了对其元素的排序。我不想暗示
集合
也不能实现
列表
接口@A.