2

我已经阅读了 Java 文档以及 LinkedHashMapskeyset()维护秩序的这篇文章。 从 LinkedHashMap 对象返回键和值的顺序是否得到保证?

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

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

就像这个答案在这篇文章中所说:使用列表还是集合更好?

返回列表与编程到最合适的接口是一致的。

返回一个集合会给用户带来歧义,因为返回的集合可能是:Set、List 或 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();
    }
}
4

3 回答 3

5

“为什么不LinkedHashMap返回保证顺序Object的类型的源代码?”SetLinkedHashSet

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

返回Set此映射中包含的键的视图。set 由 map 支持,因此对 map的更改会反映在 set 中,反之亦然。

于 2016-02-08T17:44:59.603 回答
5

它返回接口Set定义的a Map。ASet只是不包含重复元素的集合。另一方面,aList是有序集合(也称为序列)。该List接口没有指定元素是唯一的。

尽管如此,该LinkedHashMap实现实际上返回了底层的 keySet ,它是 a LinkedKeySet,并且 the 的forEach()方法LinkedKeySet是保序的,即:

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

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

于 2016-02-08T17:26:22.387 回答
1

如果它保证顺序,那么为什么 LinkedHashMap 的源代码不返回像 LinkedHashSet 一样保证顺序的 Set 类型的对象?

键集的声明类型是从 声明的类型中提取的Map.keySet()LinkedHashMap在协变返回类型被添加到 Java 语言之前被添加到标准库中。那时,除了使用 type 之外别无他法Set

无论如何,仅仅因为键集必须与底层映射具有相同的顺序并不意味着它必须是 a LinkedHashSet,事实上它不能是,因为它一定不支持元素添加。它的类是 class 的私有嵌套类LinkedHashMap。该类之间没有公共类型,这SetSet作为返回类型更有用。

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

无论如何,我不觉得你引用的关于返回 a Listvs a的摘录Collection很有说服力。事实上,关于对象的特定类的模糊性本质上不是问题。在Collectionvs.的List例子中,如果 typeCollection很好地捕捉到了方法的返回类型要求,没有特别的理由List需要 a 的特征,那么Collection返回类型是一个不错的选择。如果 a 也可以满足要求,那就太好了Set,因为这样 API 就不会在两个同样好的替代方案之间做出本质上任意的选择。

有一种思想流派认为,方法的参数类型应尽可能通用,返回类型应尽可能具体。我认为这个想法有很多优点,但它更像是一个指导方针而不是规则,关于“尽可能具体”的具体程度还有很大的解释空间。

于 2016-02-08T18:01:37.477 回答