//LinkedHashMap的entry继承自HashMap的Entry。
private static class Entry<K,V> extends HashMap.Entry<K,V> {
// These fields comprise the doubly linked list used for iteration.
//通过上面这句源码的解释,我们可以知道这两个字段,是用来给迭代时使用的,相当于一个双向链表,实际上用的时候,操作LinkedHashMap的entry和操作HashMap的Entry是一样的,只操作相同的四个属性,这两个字段是由linkedHashMap中一些方法所操作。所以LinkedHashMap的很多方法度是直接继承自HashMap。
//before:指向前一个entry元素。after:指向后一个entry元素
Entry<K,V> before, after;
//使用的是HashMap的Entry构造
Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
super(hash, key, value, next);
}
//下面是维护这个双向循环链表的一些操作。在HashMap中没有这些操作,因为HashMap不需要维护, /** * Removes this entry from the linked list. */ //我们知道在双向循环链表时移除一个元素需要进行哪些操作把,比如有A,B,C,将B移除,那么A.next要指向c,c.before要指向A。下面就是进行这样的操作,但是会有点绕,他省略了一些东西。 //有的人会问,要是删除的是最后一个元素呢,那这个方法还适用吗?有这个疑问的人应该注意一下这个是双向循环链表,双向,删除哪个度适用。 private void remove() { //this.before.after = this.after; //this.after.before = this.before; 这样看可能会更好理解,this指的就是要删除的哪个元素。
before.after = after; after.before = before; }
</span><span style="color: #008000;">/**</span><span style="color: #008000;">
* Inserts this entry before the specified existing entry in the list.
</span><span style="color: #008000;">*/<br>//插入一个元素之后做的一些操作,就是将第一个元素,和最后一个元素的一些指向改变。传进来的existingEntry就是header。<br></span>
<span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span> addBefore(Entry<K,V><span style="color: #000000;"> existingEntry) {
after </span>=<span style="color: #000000;"> existingEntry;
before </span>=<span style="color: #000000;"> existingEntry.before;
before.after </span>= <span style="color: #0000ff;">this</span><span style="color: #000000;">;
after.before </span>= <span style="color: #0000ff;">this</span><span style="color: #000000;">;
}
</span><span style="color: #008000;">/**</span><span style="color: #008000;">
* This method is invoked by the superclass whenever the value
* of a pre-existing entry is read by Map.get or modified by Map.set.
* If the enclosing Map is access-ordered, it moves the entry
* to the end of the list; otherwise, it does nothing.
</span><span style="color: #008000;">*/<br>//这个方法就是我们一开始说的,accessOrder为true时,就是使用的访问顺序,访问次数最少到访问次数最多,此时要做特殊处理。处理机制就是访问了一次,就将自己往后移一位,这里就是先将自己删除了,然后在把自己添加,<br>//这样,近期访问的少的就在链表的开始,最近访问的元素就会在链表的末尾。如果为false。那么默认就是插入顺序,直接通过链表的特点就能依次找到插入元素,不用做特殊处理。<br></span>
<span style="color: #0000ff;">void</span> recordAccess(HashMap<K,V><span style="color: #000000;"> m) {
LinkedHashMap</span><K,V> lm = (LinkedHashMap<K,V><span style="color: #000000;">)m;
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (lm.accessOrder) {
lm.modCount</span>++<span style="color: #000000;">;
remove();
addBefore(lm.header);
}
}
</span><span style="color: #0000ff;">void</span> recordRemoval(HashMap<K,V><span style="color: #000000;"> m) {
remove();
}
}</span></pre>
//重写的createEntry,这里要注意的是,新元素放桶中,是放第一位,而不是往后追加,所以下面方法中前面三行应该知道了 void createEntry(int hash, K key, V value, int bucketIndex) { HashMap.Entry<K,V> old = table[bucketIndex]; Entry<K,V> e = new Entry<>(hash, key, value, old); table[bucketIndex] = e; //这个方法的作用就是将e放在双向循环链表的末尾,需要将一些指向进行修改的操作。。 e.addBefore(header); size++; }
//这个也非常简单,无非就是对双向循环链表进行遍历。
private abstract class LinkedHashIterator<T> implements Iterator<T> {
//先拿到header的after指向的元素,也就是第一个元素。
Entry<K,V> nextEntry = header.after;
//记录前一个元素是谁,因为刚到第一个元素,第一个元素之前的元素理论上就是null。实际上是指向最后一个元素的。知道就行。
Entry<K,V> lastReturned = null;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
//判断有没有到循环链表的末尾,就看元素的下一个是不是header。
public boolean hasNext() {
return nextEntry != header;
}
//移除操作,也就一些指向问题
public void remove() {
if (lastReturned == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException(); LinkedHashMap.this.remove(lastReturned.key);
lastReturned = null;
expectedModCount = modCount;
}
//下一个元素。一些指向问题,度是双向循环链表中的操作。
Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (nextEntry == header)
throw new NoSuchElementException();
Entry<K,V> e = lastReturned = nextEntry;
nextEntry = e.after;
return e;
}
}