今天在做一個數據讀取分析的時候發現了一個問題。按序put進HashMap,取值的時候不是按序獲得的。
1,有可能是遍歷方法的問題。
a,keySet遍歷
for (String key : map.keySet()) {
System.out.println("key= "+ key + " and value= " + map.get(key));
} 失敗
b,通過Map.entrySet使用iterator遍歷key和value
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
} 失敗
c,Entry遍歷
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
} 失敗
d,正常遍歷
for (String v : map.values()) {
System.out.println("value= " + v);
} 失敗
所有能想到的遍歷方法都是用完了,發現還是沒有解決問題!那么可能就是Map內部的原理導致的非按序存儲。
2,查看HashMap原理
// 存儲時:
int hash = key.hashCode();
int index = hash % Entry[].length;
Entry[index] = value;
// 取值時:
int hash = key.hashCode();
int index = hash % Entry[].length;
return Entry[index];
簡單的講,Map是一種結合數組和鏈表的優點的數據結構。
d
通過上圖的原理示意,其實我們可以畫出來我們的數據在HashMap中的存儲結構圖。需要注意的就是Entry里除了key和value之外還有一個next,這個next相當於鏈表中的鏈域指針。那什么情況下會用到next呢。很明顯當數據的hash值對map表長度去余時,結果相等。那么為了避免覆蓋,所以將數據按照插入時的順序鏈接到后邊。
下面就可以回答為什么按序put無序get的問題了。get的時候,首先是遍歷數組的第一個元素,然后遍歷第一個元素的鏈表。然后第二個元素,第二個元素的鏈表。。。。。So,我get到的數據極有可能是無序的了(相對於put的順序)。
對於LinkedHashMap和TreeMap。LinkedHashMap與HashMap不同之處在於,它保留了一個‘前驅鏈域’和一個后繼鏈域。get的時候是按照put的順序讀取的。
1 HashMap里面存入的鍵值對在取出的時候是隨機的,也是我們最常用的一個Map.它根據鍵的HashCode值存儲數據,根據鍵可以直接獲取它的值,具有很快的訪問速度。在Map 中插入、刪除和定位元素,HashMap 是最好的選擇。
2.TreeMap取出來的是排序后的鍵值對。但如果您要按自然順序或自定義順序遍歷鍵,那么TreeMap會更好。
3. LinkedHashMap 是HashMap的一個子類,如果需要輸出的順序和輸入的相同,那么用LinkedHashMap可以實現