为什么 LinkedHashMap keyset() return LinkedHashSet 与 Set 不同?

Why doesn't LinkedHashMap keyset() return LinkedHashSet vs Set?

我已阅读 java 文档以及此 post 中,LinkedHashMaps 的 keyset() 维持秩序。 Is the order guaranteed for the return of keys and values from a LinkedHashMap object?

我的问题是,如果它保证顺序那么为什么 LinkedHashMap return 的源代码不是 Set 类型的对象来保证顺序 LinkedHashSet

我可能想到的一个原因是 LinkedHashSet 使用一个会增加内存分配的映射(取决于 AbstractSet 的实现方式)。是否也是因为它未来证明了键集的实现?

就像这个 post 中的回答所说:Is it better to use List or Collection?

Returning a List is in line with programming to the Highest Suitable Interface.

Returning a Collection would cause ambiguity to the user, as a returned collection could be either: Set, List or Queue.

那么,不看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();
    }
}

它 returns 一个 SetMap 接口定义。 Set 只是不包含重复元素的集合。另一方面,List 是有序集合(也称为序列)。 List 接口没有指定元素是唯一的。

不过,LinkedHashMap 实现实际上 returns 底层 keySet 是一个 LinkedKeySet,而 LinkedKeySetforEach() 方法是 order-保留,即:

//from the source code for the LinkedHashMap:
public Set<K> keySet() {
    Set<K> ks;
    return (ks = keySet) == null ? (keySet = new LinkedKeySet()) : ks;
}

因此,在这种情况下,元素既是唯一的又是有序的。

"why doesn't the source code of LinkedHashMap return an Object of type Set that guarantees order like LinkedHashSet?"

因为 LinkedHashSet 是一个具体的 class,它自己的实现维护自己的数据,并且 keyset() 方法必须 return Map,所以它不能只将关键数据复制到LinkedHashSet。请参阅 javadoc:

Returns a Set view of the keys contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa.

if it guarantees order then why doesn't the source code of LinkedHashMap return an Object of type Set that guarantees order like LinkedHashSet?

声明的键集类型取自Map.keySet()声明的类型。 LinkedHashMap 在协变 [​​=54=] 类型被添加到 Java 语言之前被添加到标准库中。那时,除了使用类型 Set.

别无选择

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

的确,我认为定义一个并不容易。将它与任何其他集合区分开来的基本特征是什么?您不能只说 "iteration order" 而不指定 什么 迭代顺序实例,并且该顺序取决于从中获取集合的 LinkedHashMap 实例。换句话说,迭代顺序是实例特征,而不是 class 特征。因此,表达作为 LinkedHashMap 键集性质的声明类型几乎不会提供任何超出 Set 提供的实际用途的信息。

无论如何,我认为您引用的关于 returning a List vs a Collection 的摘录非常有说服力。事实上,关于对象的特定 class 的歧义本身并不是问题。在 CollectionList 示例中,如果类型 Collection 很好地捕获了方法的 return 类型要求,那么没有特别的原因表明一个 List 是必需的,那么 Collection 是一个很好的选择 return 类型。如果 Set 也可以满足要求,那就特别好,因为这样 API 就不会在两个同样好的备选方案之间做出本质上任意的选择。

有一种观点认为,方法的参数类型应尽可能通用,return 类型应尽可能具体。我认为这个想法有很多优点,但它更像是一个指南而不是规则,并且对于 "as specific as possible" 的具体程度有很大的解释空间。