Java集合之LinkedHashMap常用方法解析


   最近正准備回顧一下Java,所以在此做一些記錄。

LinkedHashMap繼承了HashMap,大多數的操作調用的是HashMap的實現,在進行操作的時候多維護了一層雙向鏈表

LinkedHashMap的節點也繼承了HashMap的節點,多維護了前置節點和后置節點兩個屬性

1  static class Entry<K,V> extends HashMap.Node<K,V> {
2         Entry<K,V> before, after;
3         Entry(int hash, K key, V value, Node<K,V> next) {
4             super(hash, key, value, next);
5         }
6     }
View Code

1.put(K key, V value) 存放一個鍵值對,其實是調用了HashMap的put方法,通過重寫HashMap里的部分方法來實現鏈表的維護

 1 HashMap的put方法會生成一個節點,調用了newNode方法,而LinkedHashMap重寫了此方法
 2  /**
 3      * 創建一個節點
 4      * @param hash  hash值
 5      * @param key   鍵
 6      * @param value 值
 7      * @param e     下一個節點,這個是HashMap節點的屬性
 8      * @return
 9      */
10     Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
11         //調用構造方法
12         LinkedHashMap.Entry<K,V> p =
13             new LinkedHashMap.Entry<K,V>(hash, key, value, e);
14         //維護鏈表
15         linkNodeLast(p);
16         return p;
17     }
18 
19 /**
20      * 添加一個節點到末尾
21      * @param p 節點
22      */
23     private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
24         //保存尾部節點
25         LinkedHashMap.Entry<K,V> last = tail;
26         //更新尾部節點
27         tail = p;
28         //判斷之前的尾部節點是否為空
29         if (last == null)
30             //之前的尾部節點為空,說明還沒有數據,設置一下頭節點
31             head = p;
32         else {
33             //說明之前已經有數據了,將新的節點作為尾部節點連接起來
34             p.before = last;
35             last.after = p;
36         }
37     }
38 
39 HashMap當put一個已經存在的key時,會觸發是否更新的操作,之后會調用afterNodeAccess方法,LinkedHashMap重寫了此方法
40 /**
41      * accessOrder為true時,將操作的節點移到鏈表尾部
42      * @param e 節點
43      */
44     void afterNodeAccess(Node<K,V> e) {
45         LinkedHashMap.Entry<K,V> last;
46         //accessOrder 這個參數是指在進行操作的時候,是否將操作的節點移動到鏈表的最后,默認false
47         //也就是說accessOrder為false的時候鏈表就是按照插入順序維護的
48         //true的時候,會將最近使用的節點移動到鏈表最后
49         if (accessOrder && (last = tail) != e) {
50             //保存當前節點和其前置節點和后置節點
51             LinkedHashMap.Entry<K,V> p =
52                 (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
53             //清空后置節點,因為當前節點要被移動到最后了
54             p.after = null;
55             //判斷前置節點是否為空節點
56             if (b == null)
57                 //前置節點為空,說明當前節點是頭節點,將它的后置節點也就是第二個節點設置為頭節點
58                 head = a;
59             else
60                 //存在前置節點,將前置節點的后置節點連接到當前節點的下一個節點
61                 b.after = a;
62             //判斷后置節點是否為空
63             if (a != null)
64                 //后置節點不為空,更新后置節點的前置節點
65                 a.before = b;
66             else
67                 //說明該節點就是尾部節點,設置前置節點為后節點
68                 //a == null 說明p就是尾部節點? 有點不清楚
69                 last = b;
70             //統一更新尾部節點
71             if (last == null)
72                 //說明只有這么一個節點
73                 head = p;
74             else {
75                 //將當前節點掛到鏈表末尾
76                 p.before = last;
77                 last.after = p;
78             }
79             //設置尾部節點
80             tail = p;
81             ++modCount;
82         }
83     }
84 
85 LinkedHashMap也重寫了afterNodeInsertion方法
86 void afterNodeInsertion(boolean evict) {
87         LinkedHashMap.Entry<K,V> first;
88         if (evict && (first = head) != null && removeEldestEntry(first)) {
89             K key = first.key;
90             removeNode(hash(key), key, null, false, true);
91         }
92     }
93 
94 protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
95         return false;
96     }
97 
98 其實LinkedHashMap中這個方法並不生效
View Code

2.get(Object key) 根據key獲取值

 1 /**
 2      * 獲取值
 3      * @param key 鍵
 4      * @return
 5      */
 6     public V get(Object key) {
 7         Node<K,V> e;
 8         //調用了HashMap中的getNode方法
 9         if ((e = getNode(hash(key), key)) == null)
10             return null;
11         if (accessOrder)
12             //移動當前操作的節點到鏈表最后
13             afterNodeAccess(e);
14         return e.value;
15     }
View Code

3. containsValue(Object value) 是否存在某個值

1  public boolean containsValue(Object value) {
2         //通過遍歷鏈表實現
3         for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
4             V v = e.value;
5             if (v == value || (value != null && value.equals(v)))
6                 return true;
7         }
8         return false;
9     }
View Code

4.remove(Object key)  刪除key

 1 LinkedHashMap調用了HashMap的remove方法
 2 重寫了afterNodeRemoval方法
 3  /**
 4      * 刪除鏈表中的節點
 5      * @param e
 6      */
 7     void afterNodeRemoval(Node<K,V> e) {
 8         //獲取當前節點的前置后置節點
 9         LinkedHashMap.Entry<K,V> p =
10             (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
11         //清空前置后置節點
12         p.before = p.after = null;
13         
14         if (b == null)
15             //前置節點為空,說明為頭節點,更新頭節點為后置節點
16             head = a;
17         else
18             //前置節點不為空,設置前置節點的后置節點為刪除節點的后置節點
19             b.after = a;
20         if (a == null)
21             //后置節點為空,說明為尾部節點,更新尾部節點為其前置節點
22             tail = b;
23         else
24             //后置節點不為空,更新后置節點的前置節點
25             a.before = b;
26     }
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM