是否有可能在双向链接列表的帮助下以两种方式迭代LinkedHashMap?
答案 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
请注意,通过这种方式,您可以打破课程的预期设计。您应该知道为什么反射气馁一般。如果设计师将来更改类的实现,您的代码将会中断。