-
继承了HashMap,并重写了hashMap的 newNode(hash,key,value,null),newTreeNode(hash,key,value,next) 方法。
-
当accessOrder为false时(默认值),LinkedHashMap按照元素的插入顺序进行遍历。此时,双向链表的作用主要是记录元素的插入顺序,使得LinkedHashMap能够像List那样按照元素插入的顺序进行迭代。
-
当accessOrder为true时,LinkedHashMap则会按照元素的访问顺序进行遍历。这意味着,每次访问(通过get或put方法)一个元素时,该元素都会被移动到双向链表的末尾。这样,最近访问的元素就会出现在链表的末尾,而最久未访问的元素则会出现在链表的开头。
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
LinkedHashMapEntry<K,V> p =
new LinkedHashMapEntry<>(hash, key, value, e);
linkNodeLast(p);
return p;
}
TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
TreeNode<K,V> p = new TreeNode<>(hash, key, value, next);
linkNodeLast(p);
return p;
}
//双向链表添加数据
private void linkNodeLast(LinkedHashMapEntry<K,V> p) {
LinkedHashMapEntry<K,V> last = tail;
tail = p;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
}
- 继承了HashMap ,并重写afterNodeAccess()方法,e表示当前要插入的新节点在hashMap中是存在,已经进行了旧值替换新值,现在要做的就是把 e的前一个节点的after指向e的后一个节点,e的后一个节点的before指向e的前一个节点,然后e的before指向last尾部节点,last尾部节点的after指向e节点,此时e节点 变成tail节点.
//调整调整双向链表中的节点顺序,把e节点放到双向链表的尾部
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMapEntry<K,V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMapEntry<K,V> p = (LinkedHashMapEntry<K,V>)e;
LinkedHashMapEntry<K,V> b = p.before;//e节点的前一个节点
LinkedHashMapEntry<K,V> a = p.after;//e节点的后一个节点
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;
}
}
- 当调用get方法获取元素时,也会调用afterNodeAccess(e),把当前对象移动到链表的尾部
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;
}