LinkedHashMap继承自HashMap,实现了Map接口。
LinkedHashMap保持了内部数据为插入的顺序。因为LinkedHashMap用双向链表维持内部数据。
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) {
//直接使用HashMap的构造方法
super(hash, key, value, next);
}
}
LinkedHashMap还用两个变量记录了数据的首项和尾项,以保证记录插入的数据顺序。
transient LinkedHashMap.Entry<K,V> head; //记录首项数据
transient LinkedHashMap.Entry<K,V> tail; //记录尾项数据
LinkedHashMap另外一个重要的变量就是accessOrder来控制内部排序顺序
//如果为true,按照存取顺序排序;如果为false,按照插入顺序排序。
//默认为false
final boolean accessOrder;
//使用构造方法,可以指定排序规则
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
LinkedHashMap没有put(K key, V value)和remove(Object key)方法,而是直接使用了父类HashMap的方法,但是LinkedHashMap为了保持自己的特性,重写了afterNodeAccess(Node<K,V>
e)和afterNodeRemoval(Node<K,V>
e)方法。
LinkedHashMap在插入数据后会调用afterNodeAccess(Node<K,V>
e)方法。
void afterNodeAccess(Node<K,V> e) {
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;
p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a != null)
a.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}
删除数据后会调用LinkedHashMap重写的afterNodeRemoval(Node<K,V> e)
方法
//默认采用插入顺序排序时,删除数据会调用该方法
void afterNodeRemoval(Node<K,V> e) { // unlink
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
//把该项数据前后置为null,断开连接
p.before = p.after = null;
if (b == null) //删除的是第二项数据
head = a;
else
b.after = a;
if (a == null) //删除的是倒数第二项数据
tail = b;
else
a.before = b;
}
get(Object key)方法
public V get(Object key) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null) //调用父类getNode方法
return null;
if (accessOrder) //使用存取顺序排序,对内部重新进行排序
afterNodeAccess(e);
return e.value;
}
总结
- LinkedHashMap内部使用数组(也叫桶)、双向链表维护内部数据。
- LinkedHashMap会对内部数据进行排序,默认使用插入顺序的排序规则,也可以指定排序规则按存取顺序排序。
JDK版本1.8.0_92。