- LinkedHashMap是HashMap的一个子类 其在HashMap的基础上添加了一个双向链表来保证元素的插入和取出顺序一致性
那么LinkedHashMap是如何通过双向链表来保证元素的插入有序性的 ?
-
LinkedHashMap在添加数据时 把元素添加到散列表的基础之上 还会把元素插入到维护的双向链表的尾部 (如此 在遍历LinkedHashMap时 直接遍历双向链表即可)
-
而HashMap在遍历时 会遍历一整个散列表 所以HashMap的遍历速度和其数组的长度有关系 而LinkedHashMap的遍历速度只和元素数量有关系
-
总体来讲 LinkedHashMap的速度要低于HashMap 如下这一种情况除外
- 特殊情况 : 当其数组长度很长 而具体元素很少时 其遍历速度要低于LinkedHashMap
- 特殊情况 : 当其数组长度很长 而具体元素很少时 其遍历速度要低于LinkedHashMap
-
其中数组1 - 7是散列表元素的添加顺序
-
红线表示双向链表的顺序 其中1为头节点 7为尾节点
-
如果按照上面的这种情况来看 当我们遍历hashMap时 其结果为 1 6 7 3 5 2 4 如果使用LinkedHashMap就是1 2 3 4 5 6 7
我们发现在HashMap的添加和删除方法中 分别调用了如下两个方法 就是对双向链表的操作
//删除e节点
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;//把e节点的前后指向置空
//当e的前后节点不为空时 把e的前后两个节点相互指向对方
if (b == null)
head = a;
else
b.after = a;
if (a == null)
tail = b;
else
a.before = b;
}
===================
//将当前节点放到链表的尾部
void afterNodeAccess(Node<K,V> e) {
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;//使p=e的后一个节点为空
if (b == null)//当p=e的前一个节点为空时 说明p=e节点为头节点
head = a;//删除p节点后 则p的下一个节点为头节点
else
b.after = a;//否则b的下一个节点为a
if (a != null)//当a不为空时 a的前一个节点为b
a.before = b;
else//否则b节点为尾节点
last = b;
if (last == null)//如果last为空 此时该链表上只有一个节点
head = p;//p节点为头节点
else {//否则把p节点放到尾节点
p.before = last;
last.after = p;
}
tail = p;//令尾节点为p
++modCount;
}
}
LinkedHashMap的完整源码
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {
/**
* 和HashMap相比较 : LinkedHashMap的数据插入是有序的(可以理解为是先进先出)
* 而HashMap取出元素的顺序并不是插入的顺序
* LinkedHashMap在HashMap的基础上额外维护了一个双向链表 已保证其数据插入和取出的有序性
*/
//节点子类 使用的HashMap的内部节点类
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);
}
}
private static final long serialVersionUID = 3801124242820219131L;
//双向链表的头节点(最大的)
transient LinkedHashMap.Entry<K,V> head;
//双向链表的尾节点(最小的)
transient LinkedHashMap.Entry<K,V> tail;
//对于accessOrder = false,表示根据插入的顺序来排序,就是先进先出
//对于accessOrder = true,首先根据访问顺序排序,在访问次数相同情况下,根据插入顺序排序。
final boolean 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;
}
}
// 将src的链接应用到dst(用dst节点替换src节点)
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;
}
// 用next节点替换p节点
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;
}
//使用next节点替换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;
}
//删除e节点
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;//把e节点的前后指向置空
//当e的前后节点不为空时 把e的前后两个节点相互指向对方
if (b == null)
head = a;
else
b.after = a;
if (a == null)
tail = b;
else
a.before = b;
}
void afterNodeInsertion(boolean evict) {
LinkedHashMap.Entry<K,V> first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
//将当前节点放到链表的尾部
void afterNodeAccess(Node<K,V> e) {
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;//使p=e的后一个节点为空
if (b == null)//当p=e的前一个节点为空时 说明p=e节点为头节点
head = a;//删除p节点后 则p的下一个节点为头节点
else
b.after = a;//否则b的下一个节点为a
if (a != null)//当a不为空时 a的前一个节点为b
a.before = b;
else//否则b节点为尾节点
last = b;
if (last == null)//如果last为空 此时该链表上只有一个节点
head = p;//p节点为头节点
else {//否则把p节点放到尾节点
p.before = last;
last.after = p;
}
tail = p;//令尾节点为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;
}
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
public LinkedHashMap() {
super();
accessOrder = false;
}
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
putMapEntries(m, false);
}
public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
//判断集合里是否存在该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;
}
//根据key获取value值
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;
}
//如果数组里不存在key值 则返回defaultValue 否则当accessOrder为true时 把当前节点放到链表尾部并返回节点值
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;
}
//清理集合
public void clear() {
super.clear();
head = tail = null;
}
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
//获取集合所有键的集合
public Set<K> keySet() {
Set<K> ks;
return (ks = keySet) == null ? (keySet = new LinkedKeySet()) : 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;
return (vs = values) == null ? (values = new LinkedValues()) : 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(); }
}
}