LinkedHashMap 其继承了HashMap,提供了顺序保存,是通过对(键 值对)维护一个双向链表来实现的。
其提供的内部排序分为两种:访问顺序排序(ture)和 存储顺序排序(false),是通过布尔型变量accessOrder控制的;默认为false;
1.构造函数介绍
与HashMap类似,有疑问可看博主 关于HashMap源码介绍
源码:
/**
* 与HashMap初始化类似
*/
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;
}
/**
*与HashMap初始化类似
*/
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
/**
*与HashMap初始化类似
*/
public LinkedHashMap() {
super();
accessOrder = false;
}
/**
*与HashMap初始化类似
*/
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
//HashMap中的方法
putMapEntries(m, false);
}
/**
*与HashMap初始化类似
* @param initialCapacity map容量
* @param loadFactor 负载系数
* @param accessOrder 内部排序方式: 访问顺序排序(ture) ; 存储顺序排序(false)
*/
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
2.存入-put,获取-get、getOrDefault 删除-remove
其中put方法是调用HashMap中的,
get和remove是重写的HashMap方法
重要的是是重写了一些回调方法afterNodeAccess、afterNodeInsertion
(1)afterNodeAccess(Node<K,V> e) :将新更新的节点放在双向链表最后,若 accessOrder=true时还会将访问过得数据放在链表末尾
(2)afterNodeInsertion(boolean evict):是用与插入新元素是否需要删除头部元素,一般不会删除,只有重写其内部的方法removeEldestEntry(Map.Entry<K,V> eldest)才会实现删除,并且参数evict=true
源码:
/**
* 是用与插入新元素是否需要删除头部元素,一般不会删除,
* 只有重写其内部的方法removeEldestEntry(Map.Entry<K,V> eldest)才会实现删除,并且参数evict=true
*/
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry<K,V> first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
/**
* put使用存在的key和get使用
* 将新更新的节点放在双向链表最后
* 全局变量 head(存储链表头部),tail (存储链表尾部)
*/
void afterNodeAccess(Node<K,V> e) {
//临时存储尾部
LinkedHashMap.Entry<K,V> last;
//LinkedHashMap设置了操作排序,并且e不是尾部节点
if (accessOrder && (last = tail) != e) {
//用p存储当前节点e, b存储p(e)的上一个节点,a存储p(e)的下一个节点
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
//令p的下一个节点指向null(尾部节点的after一定的是null,头部节点的before为null)
p.after = null;
//b==null 标识p(e)的上一个节点为null,也就是p为 头部节点的before为null);
//需要将p下一个节点设置为头结点
if (b == null)
head = a;
//b!=null 标识p(e)的上一个节点存在值,也就是p不为头部节点的before为null);
//需要将p的上一个节点指向p的下一个节点(此处注意p的下一个节点并没有指向p的上一个节点)
else
b.after = a;
//a != null p的下一个节点不是空,也就是p不是尾部;
//那么将a(p下一个节点)的上一个节点指向 b(p的上一个节点)
if (a != null)
a.before = b;
//a == null a(p的下一个节点)为空,也就是p是尾部;
//last 的引用指向b(p的上一个节点)的
else
last = b;
//如果 last == null ,头部为p
if (last == null)
head = p;
//如果 last != null ,p的上一个节点指向last,last的下一个节点指向p
else {
p.before = last;
last.after = p;
}
//尾部指向新加的节点p
tail = p;
++modCount;
}
}
3.删除Node节点回调
删除节点后会维护链表,维护其头尾部变化。
源码:
//删除node
//全局变量 head(存储链表头部),tail (存储链表尾部)
void afterNodeRemoval(Node<K,V> e) { // unlink
//用p存储当前节点e, b存储p(e)的上一个节点,a存储p(e)的下一个节点
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
//令p的下一个节点指向null,p的上一个节点指向null,执行完此方法,a/b/p 没有引用gc会回收
p.before = p.after = null;
//b==null 标识p(e)的上一个节点为null,也就是p为 头部节点的before为null);
//需要将p下一个节点设置为头结点
if (b == null)
head = a;
//b!=null 标识p(e)的上一个节点存在值,也就是p不为头部节点的before为null);
//需要将p的上一个节点指向p的下一个节点(此处注意p的下一个节点并没有指向p的上一个节点)
else
b.after = a;
//a == null a(p的下一个节点)为空,也就是p是尾部;
//tail 的引用指向b(p的上一个节点)的
if (a == null)
tail = b;
//a != null p的下一个节点不是空,也就是p不是尾部;
//那么将a(p下一个节点)的上一个节点指向 b(p的上一个节点)
else
a.before = b;
}
5.全部源码如下
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.util;
import java.util.function.Consumer;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.io.IOException;
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
{
/**
* HashMap.Node subclass for normal LinkedHashMap entries.
*/
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);
}
}
private static final long serialVersionUID = 3801124242820219131L;
/**
* 保存头结点引用
*/
transient LinkedHashMap.Entry<K,V> head;
/**
* 保存尾结点引用
*/
transient LinkedHashMap.Entry<K,V> tail;
/**
* ture:访问顺序排序
*false:存储顺序排序
* @serial
*/
final boolean accessOrder;
// internal utilities
// 将节点放在末尾
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;
}
}
// 具体Node和treeNode节点替换的实现
private void transferLinks(LinkedHashMap.Entry<K,V> src,
LinkedHashMap.Entry<K,V> dst) {
LinkedHashMap.Entry<K,V> b = dst.before = src.before;
LinkedHashMap.Entry<K,V> a = dst.after = src.after;
if (b == null)
head = dst;
else
b.after = dst;
if (a == null)
tail = dst;
else
a.before = dst;
}
// HashMap钩子方法的重写
void reinitialize() {
super.reinitialize();
head = tail = null;
}
//创建新的节点,将新节点放在双向链表结尾
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;
}
//普通Node节点替换方法
Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
LinkedHashMap.Entry<K,V> t =
new LinkedHashMap.Entry<K,V>(q.hash, q.key, q.value, next);
transferLinks(q, t);
return t;
}
//创建新的树节点
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);
return p;
}
//树节点替换方法
TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
TreeNode<K,V> t = new TreeNode<K,V>(q.hash, q.key, q.value, next);
transferLinks(q, t);
return t;
}
//删除node
//全局变量 head(存储链表头部),tail (存储链表尾部)
void afterNodeRemoval(Node<K,V> e) { // unlink
//用p存储当前节点e, b存储p(e)的上一个节点,a存储p(e)的下一个节点
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
//令p的下一个节点指向null,p的上一个节点指向null,执行完此方法,a/b/p 没有引用gc会回收
p.before = p.after = null;
//b==null 标识p(e)的上一个节点为null,也就是p为 头部节点的before为null);
//需要将p下一个节点设置为头结点
if (b == null)
head = a;
//b!=null 标识p(e)的上一个节点存在值,也就是p不为头部节点的before为null);
//需要将p的上一个节点指向p的下一个节点(此处注意p的下一个节点并没有指向p的上一个节点)
else
b.after = a;
//a == null a(p的下一个节点)为空,也就是p是尾部;
//tail 的引用指向b(p的上一个节点)的
if (a == null)
tail = b;
//a != null p的下一个节点不是空,也就是p不是尾部;
//那么将a(p下一个节点)的上一个节点指向 b(p的上一个节点)
else
a.before = b;
}
/**
* 是用与插入新元素是否需要删除头部元素,一般不会删除,
* 只有重写其内部的方法removeEldestEntry(Map.Entry<K,V> eldest)才会实现删除,并且参数evict=true
*/
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry<K,V> first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
/**
* put使用存在的key和get使用
* 将新更新的节点放在双向链表最后
* 全局变量 head(存储链表头部),tail (存储链表尾部)
*/
void afterNodeAccess(Node<K,V> e) {
//临时存储尾部
LinkedHashMap.Entry<K,V> last;
//LinkedHashMap设置了操作排序,并且e不是尾部节点
if (accessOrder && (last = tail) != e) {
//用p存储当前节点e, b存储p(e)的上一个节点,a存储p(e)的下一个节点
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
//令p的下一个节点指向null(尾部节点的after一定的是null,头部节点的before为null)
p.after = null;
//b==null 标识p(e)的上一个节点为null,也就是p为 头部节点的before为null);
//需要将p下一个节点设置为头结点
if (b == null)
head = a;
//b!=null 标识p(e)的上一个节点存在值,也就是p不为头部节点的before为null);
//需要将p的上一个节点指向p的下一个节点(此处注意p的下一个节点并没有指向p的上一个节点)
else
b.after = a;
//a != null p的下一个节点不是空,也就是p不是尾部;
//那么将a(p下一个节点)的上一个节点指向 b(p的上一个节点)
if (a != null)
a.before = b;
//a == null a(p的下一个节点)为空,也就是p是尾部;
//last 的引用指向b(p的上一个节点)的
else
last = b;
//如果 last == null ,头部为p
if (last == null)
head = p;
//如果 last != null ,p的上一个节点指向last,last的下一个节点指向p
else {
p.before = last;
last.after = p;
}
//尾部指向新加的节点p
tail = p;
++modCount;
}
}
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
s.writeObject(e.key);
s.writeObject(e.value);
}
}
/**
* 与HashMap初始化类似
*/
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;
}
/**
*与HashMap初始化类似
*/
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
/**
*与HashMap初始化类似
*/
public LinkedHashMap() {
super();
accessOrder = false;
}
/**
*与HashMap初始化类似
*/
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
//HashMap中的方法
putMapEntries(m, false);
}
/**
*与HashMap初始化类似
* @param initialCapacity map容量
* @param loadFactor 负载系数
* @param accessOrder 内部排序方式: 访问顺序排序(ture) ; 存储顺序排序(false)
*/
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
/**
* Returns <tt>true</tt> if this map maps one or more keys to the
* specified value.
*
* @param value value whose presence in this map is to be tested
* @return <tt>true</tt> if this map maps one or more keys to the
* specified value
*/
public boolean containsValue(Object value) {
for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
V v = e.value;
if (v == value || (value != null && value.equals(v)))
return true;
}
return false;
}
/**
* 重写了HashMap get方法
*/
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;
}
/**
* {@inheritDoc}
*/
public V getOrDefault(Object key, V defaultValue) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null)
return defaultValue;
if (accessOrder)
afterNodeAccess(e);
return e.value;
}
/**
* 清空,与HashMap相比 多了个维护链表头、尾部
*/
public void clear() {
super.clear();
head = tail = null;
}
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new LinkedKeySet();
keySet = ks;
}
return ks;
}
final class LinkedKeySet extends AbstractSet<K> {
public final int size() { return size; }
public final void clear() { LinkedHashMap.this.clear(); }
public final Iterator<K> iterator() {
return new LinkedKeyIterator();
}
public final boolean contains(Object o) { return containsKey(o); }
public final boolean remove(Object key) {
return removeNode(hash(key), key, null, false, true) != null;
}
public final Spliterator<K> spliterator() {
return Spliterators.spliterator(this, Spliterator.SIZED |
Spliterator.ORDERED |
Spliterator.DISTINCT);
}
public final void forEach(Consumer<? super K> action) {
if (action == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
action.accept(e.key);
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
public Collection<V> values() {
Collection<V> vs = values;
if (vs == null) {
vs = new LinkedValues();
values = vs;
}
return vs;
}
final class LinkedValues extends AbstractCollection<V> {
public final int size() { return size; }
public final void clear() { LinkedHashMap.this.clear(); }
public final Iterator<V> iterator() {
return new LinkedValueIterator();
}
public final boolean contains(Object o) { return containsValue(o); }
public final Spliterator<V> spliterator() {
return Spliterators.spliterator(this, Spliterator.SIZED |
Spliterator.ORDERED);
}
public final void forEach(Consumer<? super V> action) {
if (action == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
action.accept(e.value);
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
}
final class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>> {
public final int size() { return size; }
public final void clear() { LinkedHashMap.this.clear(); }
public final Iterator<Map.Entry<K,V>> iterator() {
return new LinkedEntryIterator();
}
public final boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Node<K,V> candidate = getNode(hash(key), key);
return candidate != null && candidate.equals(e);
}
public final boolean remove(Object o) {
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Object value = e.getValue();
return removeNode(hash(key), key, value, true, true) != null;
}
return false;
}
public final Spliterator<Map.Entry<K,V>> spliterator() {
return Spliterators.spliterator(this, Spliterator.SIZED |
Spliterator.ORDERED |
Spliterator.DISTINCT);
}
public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
if (action == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
action.accept(e);
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
// Map overrides
public void forEach(BiConsumer<? super K, ? super V> action) {
if (action == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
action.accept(e.key, e.value);
if (modCount != mc)
throw new ConcurrentModificationException();
}
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
if (function == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
e.value = function.apply(e.key, e.value);
if (modCount != mc)
throw new ConcurrentModificationException();
}
// Iterators
abstract class LinkedHashIterator {
LinkedHashMap.Entry<K,V> next;
LinkedHashMap.Entry<K,V> current;
int expectedModCount;
LinkedHashIterator() {
next = head;
expectedModCount = modCount;
current = null;
}
public final boolean hasNext() {
return next != null;
}
final LinkedHashMap.Entry<K,V> nextNode() {
LinkedHashMap.Entry<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
current = e;
next = e.after;
return e;
}
public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
final class LinkedKeyIterator extends LinkedHashIterator
implements Iterator<K> {
public final K next() { return nextNode().getKey(); }
}
final class LinkedValueIterator extends LinkedHashIterator
implements Iterator<V> {
public final V next() { return nextNode().value; }
}
final class LinkedEntryIterator extends LinkedHashIterator
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry<K,V> next() { return nextNode(); }
}
}