LinkedHashMap 表示链散列映射表:继承了散列映射表HashMap,实现了Map接口。LinkedHashMap用的是访问顺序而不是插入顺序,对映射表条目进行迭代。每次调用get或put方法时,受到影响的条目都会被删除并放到链表的尾部(只有条目在链表中的位置会受影响,而散列表中的桶不会受到影响,一个条目总位于键散列码对应的桶中)。访问顺序有利于实现高速缓存的“最近最少使用”。例如,可能希望将访问频率搞得元素放在内存中,访问频率低的从数据库中读取。当表中找不到所需的元素项而表又满了,就可以将迭代器加入到表中,并将枚举的前几个元素删除。这些事近期最少使用的元素。这一过程可以自动化,只需要覆盖下面的方法:
protected boolean removeEldestEntry(Map.Entry eldest)
源码里面给了一个例子,可以缓存100个元素:
private static final int MAX_ENTRIES = 100;
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
每当方法放回true时,就添加一个新的条目,从而导致删除eldest条目。
这是为什么呢?看一下addEntry()方法就明白了:
void addEntry(int hash, K key, V value, int bucketIndex) {
createEntry(hash, key, value, bucketIndex);
// Remove eldest entry if instructed, else grow capacity if appropriate
Entry<K,V> eldest = header.after;
if (removeEldestEntry(eldest)) {
removeEntryForKey(eldest.key);
} else {
if (size >= threshold)
resize(2 * table.length);
}
}
if(removeEldestEntry(eldest))巧妙的调用了removeEldestEntry方法。
在看一下LinkedHashMap的内部迭代器,感觉写的很好(对我来讲源码写的都很好):
private abstract class HashIterator<E> implements Iterator<E> {
Entry<K,V> next; // next entry to return
int expectedModCount; // For fast-fail
int index; // current slot
Entry<K,V> current; // current entry
HashIterator() {
expectedModCount = modCount;
if (size > 0) { // advance to first entry
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
}
public final boolean hasNext() {
return next != null;
}
final Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
current = e;
return e;
}
public void remove() {
if (current == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Object k = current.key;
current = null;
HashMap.this.removeEntryForKey(k);
expectedModCount = modCount;
}
}
expectedModCount 是迭代器内部的修改计数器,初始化的时候等于集合的modCount,当一个集合有多个迭代器时,会出现一个问题:就是迭代器a在对集合进行修改前已经有其他迭代器对集合进行了结构化修改,所以会导致两个计数器数值不一致,此时就会抛出ConcurrentModificationException同时修改异常。