LinkedHashMap
简单介绍
LinkedHashMap继承自HashMap,实现了Map接口,所以LinkedHashMap是在HashMap的基础上实现的,保留了HashMap的所有特征,唯一与HashMap不同的是,LinkedHashMap是可以保证数据的迭代顺序的(可以是访问顺序,也可以是插入顺序)
属性及构造函数
LinkedHashMap的属性包括:
// 双向链表的头指针,指向第一个node节点
transient LinkedHashMap.Entry<K,V> head;
// 双向链表的尾指针,指向最后一个node节点
transient LinkedHashMap.Entry<K,V> tail;
// 标志位,为true时,表示按照访问顺序迭代,为false时,表示按照插入顺序迭代。
final boolean accessOrder;
LinkedHashMap的构造函数有以下几种:
public LinkedHashMap() {
super();
accessOrder = false;
}
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;
}
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
putMapEntries(m, false);
}
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
我们发现,LinkedHashMap默认是按照插入顺序来迭代的。
LinkedHashMap的相关方法
首先,我们来看一看LinkedHashMap的插入操作,LinkedHashMap没有自己定义一个put(),而是直接使用了HashMap中的put(),所以,它的添加操作会HashMap是一致的。
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
唯一不同的是这里,afterNodeAccess()
在HashMap中是没有实现的,而LinkedHashMap则重写了这个方法
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
// 判断是否按照访问顺序迭代,并且要移动的节点不是双链表最后一个节点
if (accessOrder && (last = tail) != e) {
// 拿到待移动节点的前驱节点、后继节点
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
// 由于要将节点移至双链表尾部,所以先将该节点的后驱节点置为null
p.after = null;
// 如果它的前驱为null,说明,前面没有节点,将头指针,指向它的后继节点。
if (b == null)
head = a;
else
// 调整节点顺序
b.after = a;
// 后继节点不为null时,重新调整前驱节点。
if (a != null)
a.before = b;
// 如果待移动节点的后继节点为null,说明,待移动节点是双链表最后一个结点
else
// p之前就是尾指针
last = b;
// 双向链表只有p一个结点,则p又是头结点也是尾节点
if (last == null)
head = p;
// 否则 将p插入链表尾部。
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}
这个方法,是在key出现重复时,调用的, 是将重复的key所对应的节点,放入到双链表的尾部。同时,在调用get()操作时,如果判断accseeOrder
为true时,也会调用这个方法。
其get()方法如下:
public V get(Object key) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null)
return null;
if (accessOrder)
afterNodeAccess(e);
return e.value;
}
LinkedHashMap其实就是比HashMap多了一个双向链表,由于维护数据的迭代顺序的。