1. 属性
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 > {
transient LinkedHashMap. Entry < K , V > head;
transient LinkedHashMap. Entry < K , V > tail;
final boolean accessOrder;
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) ;
}
}
}
LinkedHashMap 是通过哈希表和链表实现的,它通过维护一个链表来保证对哈希表迭代时的有序性,而这个有序是指键值对插入的顺序。另外,当向哈希表中重复插入某个键的时候,不会影响到原来的有序性。也就是说,假设你插入的键的顺序为 1、2、3、4,后来再次插入 2,迭代时的顺序还是 1、2、3、4,而不会因为后来插入的 2 变成 1、3、4、2(但其实我们可以改变它的规则,使它变成 1、3、4、2)。 LinkedHashMap 的实现主要分两部分,一部分是哈希表,另外一部分是链表。哈希表部分继承了 HashMap,拥有了 HashMap 那一套高效的操作,所以我们要看的就是 LinkedHashMap 中链表的部分,了解它是如何来维护有序性的。 LinkedHashMap 的大致实现如下图所示,当然链表和哈希表中相同的键值对都是指向同一个对象,这里把它们分开来画只是为了呈现出比较清晰的结构。
2. afterNodeAccess 方法
void afterNodeAccess ( Node < K , V > p) { }
void afterNodeInsertion ( boolean evict) { }
void afterNodeRemoval ( Node < K , V > p) { }
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 ;
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. afterNodeInsertion 方法
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 ) ;
}
}
4. afterNodeRemoval 方法
void afterNodeRemoval ( Node < K , V > e) {
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;
}
5. 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;
}
6. put 方法和 remove 方法
在 LinkedHashMap 的源码中没有找到 put 方法,这就说明了它并没有重写 put 方法,所以我们调用的 put 方法其实是 HashMap 的 put 方法。因为 HashMap 的 put 方法中调用了 afterNodeAccess 方法和 afterNodeInsertion 方法,已经足够保证链表的有序性了,所以它也就没有重写 put 方法了。remove 方法也是如此。