首先我们知道,HashMap遍历的顺序和插入的顺序是不一样的,而LinkedHashMap遍历的顺序和插入的顺序是一致的。看代码
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class Main{
public static void main(String[] args) {
Map<String, Integer> map2 = new HashMap<>();
map2.put("Abc", 1);
map2.put("css", 2);
map2.put("Zxe", 3);
LinkedHashMap<String, Integer> linkedHashMap2 = new LinkedHashMap<>();
linkedHashMap2.put("Abc", 1);
linkedHashMap2.put("css", 2);
linkedHashMap2.put("Zxe", 3);
for (Map.Entry entry : map2.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
for (Map.Entry entry : linkedHashMap2.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
}
打印结果如下:
css:2
Abc:1
Zxe:3
Abc:1
css:2
Zxe:3
很明显,使用LInkedHashMap遍历是有序的,而使用HashMap是无序的。
但是另外一种情况,当key为Integer时,就不一样了。
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class Main{
public static void main(String[] args) {
Map<Integer, Integer> map1 = new HashMap<>();
LinkedHashMap<Integer, Integer> linkedHashMap = new LinkedHashMap<>();
for (int i = 0; i < 5; i++){
map1.put(i, i * 2);
linkedHashMap.put(i, i * 2);
}
for (Map.Entry entry : map1.entrySet()){
System.out.println(entry.getKey() + ":" + entry.getValue());
}
for (Map.Entry entry : linkedHashMap.entrySet()){
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
}
打印结果如下:
0:0
1:2
2:4
3:6
4:8
0:0
1:2
2:4
3:6
4:8
当key为Integer传入HashMap时,它的遍历结果仍然是有序的。
原因剖析
先来看HashMap的get()方法,get()方法会传入一个key,然后计算它的hash值。
hash值计算:如果key为null就返回0;如果不是null,那么就先计算key的hashCode值,并将它右移16位和原来的hashCode值进行异或得到这个key的hash值。
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
继续看hash方法
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
猜想:之所以传入Integer时会有序,是不是因为Integer的HashCode值比较特别?
来看Integer中的hashCode代码,发现Integer对象中的hashCode方法,返回的就是当前value,所以插入的时候有序,遍历的时候也是有序的。
@Override
public int hashCode() {
return Integer.hashCode(value);
}
// 问题所在
public static int hashCode(int value) {
return value;
}
结论
当key为Integer对象时,HashMap之所以是有序的,就是因为Integer计算出来的hashCode值是有序的,因为Integer对象重写的hashCode方法中,就是直接返回的value值。