HashMap存入和取出數據順序不一致


一、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)

2. 圖解LinkedHashMap原理(JDK1.7)

總結一下:

LinkedHashMap的特點如下:

  • LinkedHashMap是繼承於HashMap,是基於HashMap和雙向鏈表來實現的。
  • HashMap無序;LinkedHashMap有序,可分為插入順序和訪問順序兩種。如果是訪問順序,那put和get操作已存在的Entry時,都會把Entry移動到雙向鏈表的表尾(其實是先刪除再插入)。
  • LinkedHashMap存取數據,還是跟HashMap一樣使用的Entry[]的方式,雙向鏈表只是為了保證順序。
  • LinkedHashMap是線程不安全的。

LinkedHashMap的使用場景:

  • LinkedHashMap可以實現LRU算法

 

 

 


免責聲明!

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



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