类继承关系:
什么是LinkedHashMap
哈希表和Map接口的链表实现,与HashMap的不同之处 在于它维护着一个双向链表,这个链表定义了迭代排序,通常是插入顺序。
* 如果将键重新插入中,则插入顺序不受影响。
LinkedHashMap数据结构
LinkedHashMap是基于HashMap实现的,只是在HashMap的基础上增加了双向链表而已。
(这里直接把上一篇的HashMap里的数据结构图简单改了下)
源码分析:
1.类继承实现
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>{
//方法....
}
LinkedHashMap继承HashMap所具有的特性基本一致,这里不重复了。(点击跳转Java集合源码实现三:HashMap(jdk1.8))。
2.成员变量
/**
* 首节点
*/
transient LinkedHashMap.Entry<K,V> head;
/**
* 尾节点
*/
transient LinkedHashMap.Entry<K,V> tail;
/**
* 排序规则方式
* true 按访问顺序排序
* false 默认按插入顺序排序
*/
final boolean accessOrder;
在hashMap的基础上又扩展了3个属性,用于双向链表。
3.LinkedHashMap中的链表节点
/**
* 继承HashMap.Node
*/
static class Entry<K,V> extends HashMap.Node<K,V> {
//before当前元素的上一个节点
//after当前元素的下一个节点
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
4.主要方法
构造方法
1.
/**
* 调用HashMap的构造方法
*/
public LinkedHashMap() {
super();
//默认按插入顺序排序
accessOrder = false;
}
2.
/**
* 调用HashMap的构造方法
*/
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
//默认按插入顺序排序
accessOrder = false;
}
3.
/**
* 调用HashMap的构造方法
*/
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
//默认按插入顺序排序
accessOrder = false;
}
4.
/**
* 调用HashMap的构造方法
*/
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
//默认按插入顺序排序
accessOrder = false;
putMapEntries(m, false);
}
5.
/**
* 调用HashMap的指定参数的构造方法
* 并且指定排序方式
*/
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
添加,删除方法
LinkedHashMap中并没有重写父类HashMap的put,remove等方法。均是调用其父类的方法实现。
afterNodeAccess方法(移动节点到最后的方法)
LinkedHashMap通过重写afterNodeAccess方法,使put()方法将节点插入到尾部。这也就是HashMap中afterNodeAccess()为空方法的原因,它是为LinkedHashMap服务的。
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
//当accessOrder为true 并且e不是最后一个节点的时
if (accessOrder && (last = tail) != e) {
//a为p的下一个节点
//b为p的上一个节点
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
//p的下一个节点置null
p.after = null;
//b==null,即当前节点为首节点,更新首节点为a
if (b == null)
head = a;
else//当前节点不是首节点,修改b的下一个节点为a
b.after = a;
if (a != null) //a!=null,即当前结点不是尾节点
a.before = b;//更新a的上一个节点为b
else
last = b;//最后一个节点更新为b
if (last == null)//如果最后一个节点为null
head = p;//首节点更新为p
else {
p.before = last;//p的上一个节点更新为最后一个节点
last.after = p;//最后一个节点的下一个节点更新为p
}
//尾节点修改为p
tail = p;
//操作次数增加
++modCount;
}
}
afterNodeRemoval方法
void afterNodeRemoval(Node<K,V> e) { // unlink
//a为p的下一个节点
//b为p的上一个节点
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.before = p.after = null;
if (b == null) //b为null,即当前节点为首节点
head = a;//更新首节点为a
else//即当前节点不是首节点
b.after = a;//更新b的下一个节点为a
if (a == null)//a为null,当前节点为尾节点
tail = b;//更新尾节点为b
else//即当前节点不是尾节点
a.before = b;//更新a的上一个节点为b
}
在移除节点时通过调用afterNodeRemoval()来更新首尾节点,与afterNodeAccess()同理。
获取元素
/**
* 获取元素
*/
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基本相同,getNode()与hash()方法都是调用HashMap的方法,唯一区别是具有排序方式,如果accessOrder为false,则不需要修改获取的元素的顺序,按默认的插入顺序排序,如果为true,需要调用afterNodeAccess()把获取的节点移动到最后。
---------------------
原文:https://blog.csdn.net/qq_23830637/article/details/79020118