从 LinkedHashMap 对象返回键和值的顺序是不是得到保证?
Posted
技术标签:
【中文标题】从 LinkedHashMap 对象返回键和值的顺序是不是得到保证?【英文标题】:Is the order guaranteed for the return of keys and values from a LinkedHashMap object?从 LinkedHashMap 对象返回键和值的顺序是否得到保证? 【发布时间】:2011-02-24 19:34:33 【问题描述】:我知道LinkedHashMap
有一个可预测的迭代顺序(插入顺序)。 LinkedHashMap.keySet()
返回的Set
和LinkedHashMap.values()
返回的Collection
是否也保持这个顺序?
【问题讨论】:
由于所有答案都解决了values()
和keySet()
的问题,因此我已将问题扩展为包括该问题。这意味着更多问题可以作为重复的问题关闭。
【参考方案1】:
Map 接口提供了三个 集合视图,允许将地图的内容视为一个集合 键、值的集合或集合 键值映射。 顺序 地图被定义为其中的顺序 地图集合上的迭代器 视图返回它们的元素。一些地图 实现,例如
TreeMap
类,作出具体保证 他们的订单;其他人,比如HashMap
class,不要。
-- Map
这个链表定义了迭代 排序,通常是顺序 其中钥匙被插入 地图(插入顺序)。
-- LinkedHashMap
所以,是的,keySet()
、values()
和 entrySet()
(提到的三个集合视图)按照内部链表使用的顺序返回值。是的,Map
和 LinkedHashMap
的 JavaDoc 保证了这一点。
毕竟这就是这门课的意义所在。
【讨论】:
使用 LinkedHashMap 对地图的迭代也比使用 HashMap 更快。 values() 返回一个集合。不是列表。它是如何保持秩序的? @DejelCollection
只是 values() 返回的基类。它返回的 Collection 的实现仍然由LinkedHashMap
控制。在LinkedHashMap
的情况下,它返回一个LinkedValues
实例,这是LinkedHashMap.java 中的一个私有类。
在我的情况下,LinkedHashMap 的键集不是地图中显示的顺序。对此非常困惑。
感谢您链接到文档(来自Map
),该文档明确地将地图的顺序与地图集合视图上的迭代器联系起来(并明确这些集合视图是什么)。这对我来说是缺失的部分。【参考方案2】:
查看源代码,看起来确实如此。 keySet()
、values()
和 entrySet()
在内部都使用相同的条目迭代器。
【讨论】:
有一个指向 repos 的链接会很酷,但我很懒 :-) 当然,这并不能保证前向兼容性。【参考方案3】:不要与返回 Set 的 LinkedHashMap.keySet()
和 LinkedHashMap.entrySet()
混淆,因此它不应该保证有序!
Set
是一个接口,HashSet
,TreeSet
等是它的实现。 Set
接口的 HashSet
实现不保证排序。但是TreeSet
可以。 LinkedHashSet
也可以。
因此,取决于Set
在LinkedHashMap
中是如何实现的,才能知道返回的 Set 引用是否保证排序。
我浏览了LinkedHashMap
的源码,看起来是这样的:
private final class KeySet extends AbstractSet<K> ...
public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E> ...
因此,LinkedHashMap/HashMap 有自己的Set
实现,即KeySet
。因此不要将其与HashSet
混淆。
此外,顺序是由元素插入存储桶的方式来维护的。查看LinkedHashMap
的addEntry(..)
方法并将其与HashMap
的方法进行比较,这突出了HashMap
和LinkedHashMap
之间的主要区别。
【讨论】:
虽然这个答案肯定提供了有用的信息,但它并没有真正回答这个问题。基本上是说他们可以有可预测的迭代顺序。【参考方案4】:你可以这样假设。 Javadoc 说“可预测的迭代顺序”,Map 中唯一可用的迭代器是那些用于 keySet()、entrySet() 和 values() 的迭代器。
因此,在没有任何进一步限定的情况下,它显然打算适用于所有这些迭代器。
【讨论】:
【参考方案5】:AFAIK 它没有记录,所以你不能“正式”假设。但是,当前的实现不太可能发生变化。
如果您想确保顺序,您可能希望遍历整个地图并将它们插入到具有您选择的顺序函数的排序集中,尽管您自然会付出性能成本。
【讨论】:
你的意思是 entrySet() 保证订单,keySet() 不保证? @kknight:我不确定。 javadoc 声明:“这个链表定义了迭代顺序,这通常是键插入映射的顺序(插入顺序)。”。但是,JDK 的 JavaDocs 通常非常模糊。 如果连entrySet()都不能保证迭代顺序,那么LinkedHashMap和HashMap有什么区别呢?我们如何利用 LinkedHashMap 实例中可预测的迭代顺序? 它肯定已记录在案。答案完全错误。【参考方案6】:查看界面,它返回一个普通的Set
,而不是SortedSet
。所以没有任何保证。
在通过查看实现(总是一个坏主意)来假设隐式保证之前,还要查看所有其他 Java 实现中的实现 :)
你最好在构造函数中创建一个带有 keySet 的 TreeSet。
【讨论】:
仔细看文档,确实有保证。正如有人已经写的那样,这就是这门课的重点。【参考方案7】:我认为你不能假定 keySet() 和 values() 的顺序。
我可以轻松地编写一个 LinkedHashMap 的实现,它返回无序的 keySet() 和 values(),只要我遵守在 Map 中定义并在 HashMap 中重写的这两个方法的约定。
【讨论】:
LinkedHashMap
类的全部目的是在迭代地图时保持元素的顺序,并且这种行为是明确指定的。如果你编写了一个子类而不遵守基类规范,那么你就大错特错了。以上是关于从 LinkedHashMap 对象返回键和值的顺序是不是得到保证?的主要内容,如果未能解决你的问题,请参考以下文章