【转载】原文链接 - (部分修改与补充)
1. 概述
在理解了介绍的HashMap
后,我们来学习LinkedHashMap
的工作原理及实现。首先还是类似的,我们写一个简单的LinkedHashMap
的程序:
1 | LinkedHashMap<String, Integer> lmap = new LinkedHashMap<String, Integer>(); |
运行结果是:
语文: 1
数学: 2
英语: 3
历史: 4
政治: 5
地理: 6
生物: 7
化学: 8
我们可以观察到,和HashMap
的运行结果不同,LinkedHashMap
的迭代输出的结果保持了插入顺序。是什么样的结构使得LinkedHashMap
具有如此特性呢?我们还是一样的看看LinkedHashMap
的内部结构,对它有一个感性的认识:
没错,正如官方文档所说:
Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order).
LinkedHashMap
是Hash
表和链表的实现,并且依靠着双向链表保证了迭代顺序是插入的顺序。
2. 三个重点实现的函数
在HashMap
中提到了下面的定义:
1 | // Callbacks to allow LinkedHashMap post-actions |
LinkedHashMap
继承于HashMap
,因此也重新实现了这3个函数,顾名思义这三个函数的作用分别是:节点访问后、节点插入后、节点移除后做一些事情。
afterNodeAccess函数
1 | void afterNodeAccess(Node<K,V> e) { // move node to last |
就是说在进行put之后就算是对节点的访问了,那么这个时候就会更新链表,把最近访问的放到最后,保证链表。
afterNodeInsertion函数
1 | void afterNodeInsertion(boolean evict) { // possibly remove eldest |
如果用户定义了removeEldestEntry
的规则,那么便可以执行相应的移除操作。
afterNodeRemoval函数
1 | void afterNodeRemoval(Node<K,V> e) { // unlink |
这个函数是在移除节点后调用的,就是将节点从双向链表中删除。
我们从上面3个函数看出来,基本上都是为了保证双向链表中的节点次序或者双向链表容量所做的一些额外的事情,目的就是保持双向链表中节点的顺序要从eldest
到youngest
。
3. put和get函数
put
函数在LinkedHashMap
中未重新实现,只是实现了afterNodeAccess
和afterNodeInsertion
两个回调函数。get
函数则重新实现并加入了afterNodeAccess
来保证访问顺序,下面是get
函数的具体实现:
1 | public V get(Object key) { |
值得注意的是,在accessOrder
模式下,只要执行get
或者put
等操作的时候,就会产生structural modification
。官方文档是这么描述的:
A structural modification is any operation that adds or deletes one or more mappings or, in the case of access-ordered linked hash maps, affects iteration order. In insertion-ordered linked hash maps, merely changing the value associated with a key that is already contained in the map is not a structural modification. In access-ordered linked hash maps, merely querying the map with get is a structural modification.
不要犯了像ConcurrentModificationException with LinkedHashMap类似的问题。
总之,LinkedHashMap不愧是HashMap的儿子,和老子太像了,当然,青出于蓝而胜于蓝,LinkedHashMap的其他的操作也基本上都是为了维护好那个具有访问顺序的双向链表。:-)
参考链接
Class LinkedHashMap
ConcurrentModificationException with LinkedHashMap