java.util.LinkedHashMap
extends HashMap<K,V> implements Map<K,V>
LinkedHashMap可以保存元素存进map中的顺序或访问元素的顺序,LinkedHashMap维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序
1.类变量&常量
transient LinkedHashMap.Entry<K,V> head; //双向链表的头部
transient LinkedHashMap.Entry<K,V> tail; //双向链表的尾部
final boolean accessOrder; //遍历该map时采用的方法,true代表访问顺序,false代表插入顺序
2.构造方法
//无参构造方法,默认容量16,装载因子.75等,采用插入顺序保存
public LinkedHashMap() {
super();
accessOrder = false;
}
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
putMapEntries(m, false); //将容器中的键值对插入到map中
}
//有初始容量的构造方法
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
//有初始容量、装载因子的构造方法
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;
}
//可以通过设置accessOrder来决定遍历时的访问顺序
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
3.内部类
1.Entry:继承自HashMap的内部类Node,且在此基础上添加了before和after,
作为LinkedHashMap的内部结点。注意Entry中也有next元素,其余before和after的代表含义不同。
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);
}
}
2.LinkedHashIterator,对LinkedHashMap进行遍历,其有三个子类,分别为
LinkedKeyIterator、LinkedValueIterator和LinkedEntryIterator,代表对
key遍历、对value遍历和对Entry遍历
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;
}
}
3.LinkedValues:得到value的容器类,其iterator方法会调用LinkedValueIterator的构造方法
4.LinkedKeySet:得到key的Set类,其iterator方法会调用LinkedKeyIterator的构造方法
5.LinkedEntrySet:得到Entry的Set类,其iterator方法会调用LinkedEntryIterator的构造方法
6.LinkedHashIterator:对LinkedHashMap做遍历时需要的内部类
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; //从head开始
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
current = e;
next = e.after; //双向链表的下一个
return e;
}
7.LinkedHashIterator的三个子类,分别代表对key、value和Entry遍历
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(); }
}
4.重要函数
1.分别得到相应的LinkedEntrySet、LinkedKeySet和LinkedValues
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
}
public Set<K> keySet() {
Set<K> ks;
return (ks = keySet) == null ? (keySet = new LinkedKeySet()) : ks;
}
public Collection<V> values() {
Collection<V> vs;
return (vs = values) == null ? (values = new LinkedValues()) : vs;
}
2.newNode方法,重写父类的newNode方法,返回一个LinkedHashMap.Entry对象,
且将该对象链接到链表的最后。注意newNode方法的调用是在putVal方法中,
新建一个newNode类,从而在这里调用LinkedHashMap的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;
}
//树节点也要放到链表的末尾
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;
}
3.linkNodeLast方法,LinkedHashMap的核心函数,将结点放到双向链表的末尾
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
LinkedHashMap.Entry<K,V> last = tail;
tail = p;
if (last == null) //说明是第一个Entry
head = p;
else { //构建双向链表
p.before = last;
last.after = p;
}
}
4.LinkedHashMap的put元素后可以进行一些操作(此时已经完成双向链表的相应插入操作)
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry<K,V> first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
//调用HashMap的removeNode方法
removeNode(hash(key), key, null, false, true);
}
}
//允许其删除最旧的元素,在被put和putAll方法时被调用,
//可以使添加新元素的同时删除旧元素。对于缓存的子类实现,该方法非常有用(需要覆盖)
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
5. get方法,根据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;
}
//afterNodeAccess方法,此方法被父类多个方法调用,如putVal方法中,
//若已有相同的key存在,则会执行该方法等
void afterNodeAccess(Node<K,V> e) {
LinkedHashMap.Entry<K,V> last;
//accessOrder=true且tail!=e,将结点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;
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;
}
下面的图展示了访问前和访问后的状态,假设访问的结点为结点3
6.表示删除节点后的相关操作,被父类的removeNode方法调用
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; //将p的before和after设为null,表示p不再在链表中
if (b == null)
head = a;
else
b.after = a;
if (a == null)
tail = b;
else
a.before = b;
}
7.containsValue是按照链表的顺序来查找value的,而不是按照桶的顺序来查找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;
}
8.transferLinks方法,用dst结点替换src结点
其中只考虑了before与after域,并没有考虑next域,next会在调用tranferLinks函数中进行设定。
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;
}