- 继承HashMap
- 有序,基于双向链表保持插入顺序或访问顺序
- 访问顺序可实现LRU缓存,会将新操作的对象放在队尾,删除时会先删除队首
- 非线程安全
主要属性和构造器
public class LinkedHashMap<K,V>
extends HashMap<K,V> implements Map<K,V>{
// 结点,个人理解继承过来是为了便于访问,不继承应该也可以访问
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) {
super(hash, key, value, next);
}
}
// 双向链表的头结点,最老结点
transient LinkedHashMap.Entry<K,V> head;
// 双向链表的尾结点,最新结点
transient LinkedHashMap.Entry<K,V> tail;
//遍历顺序: true 访问顺序、 false 插入顺序
final boolean accessOrder;
// 默认使用插入顺序
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(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
// 通过特定map实例化
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
putMapEntries(m, false);
}
}
方法
Put 方法
Put方法没重写,调用父类的方法 重写了newNode方法,在新建接结点时将结点加入双向链表的尾部
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);
return p;
}
// 将结点连接到尾部
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
LinkedHashMap.Entry<K,V> last = tail;
tail = p;
//添加第一个结点,头尾都是p
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
}
Get 方法
// 返回null 有两种可能:一、没有此key,二、此key对应的值为空
// 可通过containsKey()方法区分
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;
}
// 最常用的将其放在链表的最后,不常用的放在链表的最前
// move node to last 移动到链表尾部
void afterNodeAccess(Node<K,V> e) {
LinkedHashMap.Entry<K,V> last;
// 访问顺序,e不是尾结点
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.after = null;
// e 为头结点,将e的后继结点设为头结点
if (b == null)
head = a;
//将e的前驱结点和后继结点连接
else
b.after = a;
// e 非尾结点,将e的前驱结点设为头结点
if (a != null)
a.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}
Remove 方法
通过重写afterNodeRemoval影响删除操作
// 链表中移除结点
void afterNodeRemoval(Node<K,V> e) { // unlink
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.before = p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a == null)
tail = b;
else
a.before = b;
}
最后推荐一下我的公众号,淘宝购物返现省钱
永久海报.jpg