今天在做一个数据读取分析的时候发现了一个问题。按序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可以实现