一、HashMap 亂序問題介紹
HashMap 是我們在開發中常用的Map數據結構,它根據 HashCode的值存儲數據,根據鍵進行取值,具有很快的訪問速度。
關於HashMap的缺點我們知道它是線程不安全的,這里我們可以通過Collections.synchronizedMap()方法或者使用ConcurrentHashMap來解決同步問題。
這里要指出來的一點是,HashMap存取是亂序的,下面我們通過一個實例看一下:
public class HashMapTest { public static void main(String[] args) { Map<String, String> hashMap = new HashMap<String, String>(); hashMap.put("key0", "value0"); hashMap.put("key1", "value1"); hashMap.put("key2", "value2"); Set<Map.Entry<String, String>> set = hashMap.entrySet(); for (Map.Entry entry : set) { String key = (String) entry.getKey(); String value = (String) entry.getValue(); System.out.println("key:" + key + ",value:" + value); } } }
輸出結果:
key:key1,value:value1
key:key2,value:value2
key:key0,value:value0
可以看到,我們是按照xxx1、xxx2、xxx3的順序插入的,但是輸出結果並不是按照順序的。
此問題在實際開發中可能存在的場景:Map作為容器提交請求參數,但是如果使用HashMap進行存儲,則在用於上傳圖片的時候,會出現圖片亂序的問題。
二、解決HashMap亂序問題的方案
解決方案為:使用LinkedHashMap。
public static void main(String[] args) { Map<String, String> hashMap = new LinkedHashMap<>(); hashMap.put("key0", "value0"); hashMap.put("key1", "value1"); hashMap.put("key2", "value2"); Set<Map.Entry<String, String>> set = hashMap.entrySet(); for (Map.Entry entry : set) { String key = (String) entry.getKey(); String value = (String) entry.getValue(); System.out.println("key:" + key + ",value:" + value); } }
輸出結果:
key:key0,value:value0
key:key1,value:value1
key:key2,value:value2
三、LinkedHashMap 說明
LinkedHashMap 是HashMap的一個子類,保存了記錄的插入順序,在用Iterator遍歷LinkedHashMap時,先得到的記錄肯定是先插入的。
LinkedHashMap繼承自HashMap,是基於HashMap的基礎之上進行的擴展:
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {
構造函數基本上也是super的HashMap的構造函數,這里特別說明一下其中一個構造函數:
public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; }
前面兩個參數 initialCapacity 和 loadFactor 都是比較熟悉的,分別為初始容量和負載因子。這里我們着重說一下 accessOrder,如果將accessOrder設置為false,表示不是訪問順序而是插入順序存儲的,這也是默認值,表示LinkedHashMap中存儲的順序是按照調用put方法插入的順序進行排序的。這表示LinkedHashMap存儲順序有兩種:插入順序 和 訪問順序。
以下是兩篇很好的文章,幫助大家基於源碼理解LinkedHashMap:
1. LinkedHashMap 源碼詳細分析(JDK1.8)
總結一下:
LinkedHashMap的特點如下:
- LinkedHashMap是繼承於HashMap,是基於HashMap和雙向鏈表來實現的。
- HashMap無序;LinkedHashMap有序,可分為插入順序和訪問順序兩種。如果是訪問順序,那put和get操作已存在的Entry時,都會把Entry移動到雙向鏈表的表尾(其實是先刪除再插入)。
- LinkedHashMap存取數據,還是跟HashMap一樣使用的Entry[]的方式,雙向鏈表只是為了保證順序。
- LinkedHashMap是線程不安全的。
LinkedHashMap的使用場景:
- LinkedHashMap可以實現LRU算法