HashMap的到底是有序還是無序

前提

首先說明:HashMap不保證插入順序,但是循環遍歷時,輸出順序是不會改變的。
代碼說明:

public class HashMapTest {

    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<>();
        map.put("aaa", "aaa");
        map.put("bbb", "bbb");
        map.put("ccc", "ccc");

        System.out.println("第一次輸出:");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println(entry.getKey());
        }
        System.out.println("\n第二次輸出:");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println(entry.getKey());
        }
    }
}

輸出:

第一次輸出:
aaa
ccc
bbb

第二次輸出:
aaa
ccc
bbb

問題背景

項目開發過程中,遇到類似的如下代碼,即,兩個Map,put的key值相同,但是兩個Map最後循環遍歷輸出的key順序卻不一樣

public class HashMapTest {

    public static void main(String[] args) {
        HashMap<String, String> map1 = new HashMap<>();
        map1.put("123", "aaa");
        map1.put("23456", "bbb");

        System.out.println("map1的循環遍歷");
        for (Map.Entry<String, String> entry : map1.entrySet()) {
            System.out.println(entry.getKey());
        }

        HashMap<String, String> map2 = new HashMap<>(map1.size());
        map2.put("123", "aaa");
        map2.put("23456", "bbb");
        System.out.println("map2的循環遍歷");
        for (Map.Entry<String, String> entry : map2.entrySet()) {
            System.out.println(entry.getKey());
        }
    }
}

代碼輸出爲:

map1的循環遍歷
123
23456
map2的循環遍歷
23456
123

HashMap的一些特性

  • HashMap的數據結構:數組+單鏈表,當存在hashCode相同的不同對象時,會將value以單鏈表的形式,往後追加。數組加快訪問速度,單鏈表解決hash值衝突
  • 調用put方法時,發生了什麼:根據key的hashCode,計算出將key放入數組的index下標,index= (數組長度 - 1) & hashCode
  • HashMap循環遍歷的順序:根據數組順序+單鏈表順序進行輸出。雖然遍歷時,用的EntrySet,但是可以簡單理解爲,兩層循環輸出數據,外層循環爲遍歷數組,內層循環爲遍歷單鏈表
  • HashMap在初始化時,默認初始容量爲16,以及默認的擴容因子0.75(在此處就不詳細介紹了)

問題分析

基於如上HashMap的特性,仔細看map2的初始化,會發現

        HashMap<String, String> map2 = new HashMap<>(map1.size());

即:map2的初始化容量=map1.size()。
這個設置,導致相同的key,在put到map2時,計算出的index值,與map1中的不一樣
因爲計算index時,依賴於數組的長度(參考上面:put方法調用說明)

結論

若兩個Map的初始化容量不一致,就算同時插入相同的key,最後輸出的順序,不一定一直

再結論

代碼規範性挺重要的,想要依賴Map保持有序性,請使用LinkedHashMap

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章