java源码分析之LinkedHashMap(二)
get(Object key)
1 public V get(Object key) {
2 Entry e = (Entry)getEntry(key);
3 if (e == null)
4 return null;
5 e.recordAccess(this);
6 return e.value;
7 }
get(Object key)方法通过HashMap的getEntry(Object key)方法获取节点,并返回该节点的value值,获取节点如果为null则返回null。recordAccess(HashMap m)是LinkedHashMap的内部类Entry的一个方法,将在介绍Entry的时候进行详细的介绍。
clear()
1 public void clear() {
2 super.clear();
3 header.before = header.after = header;
4 }
clear()方法先调用父类的方法clear()方法,之后将链表的header节点的before和after引用都指向header自身,即header节点就是一个双向循环链表。这样就无法访问到原链表中剩余的其他节点,他们都将被GC回收。
以上的内容多多少少都涉及到了LinkedHashMap的内部类Entry,下面详细介绍这个内部类。
1 // 这是一个私有的、静态的内部类,继承自HashMap的Entry。
2 private static class Entry extends HashMap.Entry {
3 // 对前后节点的引用
4 Entry before, after;
5 // 构造方法直接调用父类的构造方法
6 Entry(int hash, K key, V value, HashMap.Entry next) {
7 super(hash, key, value, next);
8 }
9
10 // 移除该节点,只需修改前一节点的after引用和后一节点的before引用
11 private void remove() {
12 // 修改后该节点服务再被访问,会被GC回收
13 before.after = after;
14 after.before = before;
15 }
16
17 // 在指定节点之前插入当前节点(双向链表插入节点的过程)
18 private void addBefore(Entry existingEntry) {
19 // 将当前节点的after引用指向existingEntry
20 after = existingEntry;
21 // 将before的引用指向existingEntry节点的前一节点
22 before = existingEntry.before;
23 // 将原先existingEntry节点的前一节点的after引用指向当前节点
24 before.after = this;
25 // 将原先existingEntry节点的后一节点的before引用指向当前节点
26 after.before = this;
27 }
28
29 // 当调用此类的get方法或put方法(put方法将调用到父类HashMap.Entry的put
30 // 方法)都将调用到recordAccess(HashMap m)方法
31 // 如果accessOrder为true,即使用的是最近最少使用的次序,则将当前被修改的
32 // 节点移动到header节点之前,即链表的尾部。
33 // 这也是为什么在HashMap.Entry中有一个空的
34 // recordAccess(HashMap m)方法的原因
35 void recordAccess(HashMap m) {
36 LinkedHashMap lm = (LinkedHashMap)m;
37 if (lm.accessOrder) {
38 lm.modCount++;
39 remove();
40 addBefore(lm.header);
41 }
42 }
43 // 和recordAccess(HashMap m)方法一样,在HashMap.Entry中同样有一个对应的空方法。当进行删除(remove)操作的时候会被调用
44 void recordRemoval(HashMap m) {
45 remove();
46 }
47 }
介绍完了内部类Entry,下面是创建一个Entry节点和添加一个Entry的两个方法。
createEntry(int hash,K key,V value,int bucketIndex)
1 void createEntry(int hash, K key, V value, int bucketIndex) {
2 HashMap.Entry old = table[bucketIndex];
3 Entry e = new Entry(hash, key, value, old);
4 table[bucketIndex] = e;
5 e.addBefore(header);
6 size++;
7 }
createEntry(int hash,K key,V value,int bucketIndex)方法覆盖了父类HashMap中的方法。这个方法不会拓展table数组的大小。该方法首先保留table中bucketIndex处的节点,然后调用Entry的构造方法(将调用到父类HashMap.Entry的构造方法)添加一个节点,即将当前节点的next引用指向table[bucketIndex] 的节点,之后调用的e.addBefore(header)是修改链表,将e节点添加到header节点之前。
该方法同时在table[bucketIndex]的链表中添加了节点,也在LinkedHashMap自身的链表中添加了节点。
addEntry(int hash, K key, V value, int bucketIndex)
1 void addEntry(int hash, K key, V value, int bucketIndex) {
2 createEntry(hash, key, value, bucketIndex);
3 Entry eldest = header.after;
4 if (removeEldestEntry(eldest)) {
5 removeEntryForKey(eldest.key);
6 } else {
7 if (siz