1 背景
- LinkedHashMap继承了HashMap
- LinkedHashMap<K,V>:HashMap是以key-value形式存储数据的
- extends HashMap<K,V>:继承了HashMap,哈希表部分的功能和HashMap相似。
implements Map<K,V>:实现了Map。HashMap已经继承了Map接口,为什么LinkedHashMap还要实现Map
- LinkedHashMap还维护着一个双重链接链表
2 结构
- 因为继承了HashMap,所有结构上也是链表+数组+红黑树
- 同时因为LinkedHashMap因为是有顺序的,它包含一个贯穿于所有entry的双重链接列表。
- 大部分方法都是继承HashMap,但是也有部分关键方法是重写的
3 重写方法详解
1 LinkedHashMap 中数组中的链表节点元素对象结构
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;//前一个位置与后一个位置的节点,主要用来记载LinkedHashMap中的前后位置的节点
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
2 put是继承了父类HashMap,但是如果和父类完全一样,那肯定是不可能的,所有肯定对方法有重写
重写的方法1 :
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
LinkedHashMap.Entry<K,V> p =
new LinkedHashMap.Entry<K,V>(hash, key, value, e);
linkNodeLast(p); //该方法的作用是修改双向列表,来保持我们LinkedHashMap中记录的元素位置
return p;
}
newNode()方法被重写了,调用方式:(put(父类)---->putVal(父类)--->newNode(子类重写))
重写的方法2 :
TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
TreeNode<K,V> p = new TreeNode<K,V>(hash, key, value, next);
linkNodeLast(p);//该方法的作用是修改双向列表,来保持我们LinkedHashMap中记录的元素位置
return p;
}
newNode()方法被重写了,调用方式: put(父类)---->putVal(父类)---->putTreeVal(父类)---->newTreeNode(子类重写)
重写的方法3 :
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;
}
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;
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中有2种 排序方式:插入的顺序(accessOrder=false)\ 访问顺序(accessOrder=true)
accessOrder:通过构造方法来设置
重写排列双向链表
双向链表(插入的时候调用下面方法) 指针问题:
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;
}
}
当第一次添加元素的时候 , 头节点和尾节点 都为 这个新元素
当不是第一次添加元素的时候 把尾节点的值设置为新来的元素,然后把旧的尾节点的after指向新的尾节点,把新节点的before指向酒旧的尾节点
/** * 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;