为什么LinkedHashMap keyset()不返回LinkedHashSet vs Set?

时间:2016-02-08 17:18:54

标签: java collections linkedhashmap linkedhashset

我已经阅读过java文档,并且在这篇文章中也看过LinkedHashMaps' keyset()维持秩序。 Is the order guaranteed for the return of keys and values from a LinkedHashMap object?

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

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

就像这篇文章中的答案一样:Is it better to use List or Collection?

  

返回列表符合最高适合的编程   接口

     

返回集合会导致用户不明确,因为a   返回的集合可以是: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();
    }
}

3 个答案:

答案 0 :(得分:5)

“为什么LinkedHashMap的源代码不会返回Object SetLinkedHashSet来保证LinkedHashSet之类的订单?” < / p>

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

  

返回此地图中包含的键的{{1}}视图。 集由地图支持,因此对地图的更改会反映在集合中,反之亦然。

答案 1 :(得分:2)

它返回<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css" rel="stylesheet"/> <div class="row"> <div class="featuresanimate"> <div id="features" class="section scrollspy"> <div class="container"> <h2 style="text-decoration:underline;text-align:center;font-weight:bold;font-family:Comic Sans MS">Features</h2> <div class="features"> <div class="col s6"> <img src="http://placehold.it/100x100" height="100" width="100"> <div class="feature-set"> <h3>One</h3> <ul> <li>profile</li> <li>profile</li> <li>profile</li> <li>profile</li> </ul> </div> </div> <div class="col s6"> <img src="http://placehold.it/100x100" height="100" width="100"> <div class="feature-set"> <h3>Two</h3> <ul> <li>profile</li> <li>profile</li> <li>profile</li> <li>profile</li> </ul> </div> </div> </div> </div> </div> </div> </div>接口定义的... <?php if (have_posts()) : ?> <?php while (have_posts()) : the_post(); ?> <div class="grid_12 exhibition-views"> <div class="navigation"> <div class="previous"> <?php _e("[:en]".previous_image_link(0,'Previous')."[:de]".previous_image_link(0,'Zurück')."[:]"); ?> </div> <div class="next"> <?php _e("[:en]".next_image_link(0,'Next')."[:de]".next_image_link(0,'Weiter')."[:]"); ?> </div> </div> <?php echo wp_get_attachment_image( $post->ID, 'large' ); ?> <!-- <div class="caption">< ?php if ( !empty($post->post_excerpt) ) the_excerpt(); ? ></div> --> </div> <?php endwhile; ?> ... Set只是一个不包含重复元素的集合。另一方面,Map是有序集合(也称为序列)。 Set接口未指定元素是唯一的。

但是,List实现实际上返回了List的基础keySet,LinkedHashMap的{​​{1}}方法是保持顺序的,即:

LinkedKeySet

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

答案 2 :(得分:1)

  

如果它保证顺序那么为什么LinkedHashMap的源代码不返回类型为Set的Object,它保证了LinkedHashSet这样的顺序?

密钥集的声明类型是从Map.keySet()声明的那个中提取的。在将协变返回类型添加到Java语言之前,LinkedHashMap已添加到标准库中。那时,除了使用类型Set之外别无选择。

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

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

无论如何,我没有找到你引用的关于返回ListCollection的摘录非常有说服力的摘录。事实是,关于对象特定类的模糊性本身并不是问题。在CollectionList示例中,如果类型Collection很好地捕获了方法的返回类型要求,那么{{1}的特征特征没有特别的原因需要,然后List是返回类型的一个很好的选择。如果Collection也能满足要求,那就特别好了,因为API并没有在两个同样好的选择之间做出基本上任意的选择。

有一种思想流派认为方法应该在其参数类型中尽可能通用,并且在返回类型中尽可能具体。我认为这个想法有很多优点,但它更多的是指导而不是规则,并且对于具体的“尽可能具体”具有相当大的解释空间。