LinkedHashMap继承自HashMap。可以实现有序的map,而hashmap是无序的。所谓有序就是指迭代的时候按照某种顺序迭代。比如插入顺序,或者最近访问顺序。而不是按照key或者value的大小值排序。
其中默认是按插入顺序排序,也可以按照最近访问排序来遍历LinkedHashMap。
* <p>A special {@link #LinkedHashMap(int,float,boolean) constructor} is
* provided to create a linked hash map whose order of iteration is the order
* in which its entries were last accessed, from least-recently accessed to
* most-recently (<i>access-order</i>). This kind of map is well-suited to
* building LRU caches.
LinkedHashMap实现了Map接口,而且是以hash table和linked list相结合的方式实现,所谓的“hash table和linked list相结合”是指LinkedHashMap底层还是使用了一个数组结合hash来存储,跟HashMap一致。所谓的实现了linked list,是指LinkedHashMap内部维护一个双向列表,主要是通过如下方式实现双向列表的:
首先重新定义了Map中的Node,注意跟HashMap中的Node区分,增加了指向前一个和后一个节点的指针:
/**
* HashMap.Node subclass for normal LinkedHashMap entries.
*/
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
其次,定义了两个指针变量,分别只想链表的头和尾
/**
* The head (eldest) of the doubly linked list.
*/
transient LinkedHashMap.Entry<K,V> head;
/**
* The tail (youngest) of the doubly linked list.
*/
transient LinkedHashMap.Entry<K,V> tail;
然后在插入新元素的时候, 会调用父类HashMap的put(key, value)方法,然后父类会调用子类LinkedHashMap的new Node方法来创建新节点,并切完整链表链接操作。
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
LinkedHashMap.Entry<K,V> p =
new LinkedHashMap.Entry<>(hash, key, value, e);
linkNodeLast(p);
return p;
}
// internal utilities
// link at the end of list
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
LinkedHashMap.Entry<K,V> last = tail;
tail = p;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
}
由于LinkedHashMap地层仍采用哈希数组的方式来存储数据,所以插入和查找的速度跟HashMap不差上下。以下是官方说法:
* <p>This class provides all of the optional {@code Map} operations, and * permits null elements. Like {@code HashMap}, it provides constant-time * performance for the basic operations ({@code add}, {@code contains} and * {@code remove}), assuming the hash function disperses elements * properly among the buckets. Performance is likely to be just slightly * below that of {@code HashMap}, due to the added expense of maintaining the * linked list, with one exception: Iteration over the collection-views * of a {@code LinkedHashMap} requires time proportional to the <i>size</i> * of the map, regardless of its capacity. Iteration over a {@code HashMap} * is likely to be more expensive, requiring time proportional to its * <i>capacity</i>.
而且按照官方说法, LinkedHashMap遍历只跟LinkedHashMap中实际拥有的节点个数有关,而与Capacity没关系,而HashMap就做不到这一点,HashMap的遍历话费事件跟Capacity的大小成正比,这是因为LinkedHashMap有指针,遍历时通过指针来遍历,而HashMap需要遍历保存数据的数组的每一个元素,数组越大, Capacity越大,遍历时间越久。