是否可以在双向链接列表的帮助下实现两种方式迭代LinkedHashMap?

时间:2018-01-21 12:11:55

标签: java collections hashmap linkedhashmap

是否有可能在双向链接列表的帮助下以两种方式迭代LinkedHashMap?

2 个答案:

答案 0 :(得分:1)

不直接。 LinkedHashMap本身甚至没有提供获取迭代器的方法(除非你算上forEach()),所以你需要迭代keySet()entrySet()values()。它们仅提供常规的仅向前Iterator

可以在List中创建entrySet()。它会保留订单,然后您可以按照自己的意愿进行迭代,但是您需要承担创建List的费用。

答案 1 :(得分:0)

设计

从设计师的角度来看,从技术上讲,LinkedHashMap的当前实现是可以的。

但是他们无法访问此内容。这也允许开发人员有一天改变内部实现。如果他们提供两个迭代方向,他们将需要坚持以确保未来,以确保向后兼容性

通过文档,LinkedHashMap的唯一好处应该是确保迭代按插入顺序,仅此而已。所以它只提供了完全符合目标所需的东西。

手动(额外费用)

如果不部署反射,您将无法访问内部LinkedList,也无法在两个方向上进行迭代。

您当然可以自己手动创建LinkedList并将其用于两个方向的迭代:

LinkedHashMap<K, V> map = ...

LinkedList<Entry<K, V>> entries = new LinkedList<>(map.entrySet());
Iterator<Entry<K, V>> descIter = entries.descendingIterator();

while (descIter.hasNext()) {
    Entry<K, V> entry = descIter.next();
    ...
}

反思(无需额外费用,但不鼓励)

使用反射,您可以访问内部LinkedList,请注意,这通常是强烈劝阻。由于链接列表是手动实现的,因此并不容易,因此请参阅{em> OpenJDK版本8u40-b25 中的an implementation

首先,我们需要访问tail的{​​{1}}元素:

LinkedHashMap

因此我们需要先将其公开,然后检索值:

transient LinkedHashMap.Entry<K,V> tail;

现在,您可以按照Class<?> c = map.getClass(); Field tailField = c.getDeclaredField("tail"); tailField.setAccessible(true); Object tailValue = tailField.get(map); Entry<K, V> tail = (Entry<K, V>) tailValue; 的{​​{1}}字段开始使用尾部进行迭代:

before

迭代然后看起来像这样:

LinkedHashMap.Entry

请注意,通过这种方式,您可以打破课程的预期设计。您应该知道为什么反射气馁一般。如果设计师将来更改类的实现,您的代码将会中断。