【Java面试】彻底搞懂HashMap

废话不多说,直接阅读源码。如果你实在无闲暇看无聊的代码阅读,可以阅读每段的标题或者最后的总结。


HashMap结构

transient <K,V>[] table;

实际上HashMap内就是由多个Node<K, V>对象组成的数组,如果你暂时还不知道泛型的话,那可能还是看不明白,我用Object[]这样来解释是不是更清楚呢,虽然两者是完全不相同,但是为了理解这个东西。

而这个对象内又包含着哪些属性组成呢?

final int hash;
final K key;
V value;
Node<K,V> next;

hash则是右key通过获得对象的hashCode得到的值和hashCode之后的值无符号右移16位之后异或得到,在代码中他的算法是这样的,这里就不深究了具体怎么计算了。

key.hashCode()) ^ (h >>> 16)

后面的几个属性我们通过put方法debug看看他们是怎么被设置的吧!

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

put的核心方法在putVal中,一打开一大把的逻辑把我看晕了,我过滤掉一些无关的代码细节,直接揪出新建Node对象和设置的地方。

tab[i] = newNode(hash, key, value, null);

是不是觉得就这?但是重点了来了,next这个最重要的属性到哪里去了,但是逻辑真的好麻烦不想看,硬着头皮继续debug。

首先put两个对象,因为只有一个对象的时候,这里的next会为null。

HashMap hashMap = new HashMap();
hashMap.put("1", "1");
hashMap.put("2", "2");

直接就进到了这个方法,又是一连串的逻辑!

resize();

这里就是计算和设置next属性的地方,有兴趣的可以仔细阅读源码。


单链表

到这里如果有数据结构基础的人应该差不多明白了百分之80了,就是链表的存储结构。

如果还是不清楚的话,那么我给大家画几张图就明白了。
单链表图

无序的单链表

但是有个问题既然是数组,那么应该是有序的才对,那么为什么HashMap常常被人说是无序的呢?可能是我们漏看了哪里,我们从遍历的顺序来看看到底什么原因。

 HashMap hashMap = new HashMap();

for (int i = 0; i < 1000; i++) {
    hashMap.put(String.valueOf(i), String.valueOf(i));
}

Iterator it = hashMap.entrySet().iterator();
while (it.hasNext()) {
    Map.Entry entry = (Map.Entry) it.next();
    String key = (String) entry.getKey();
    String value = (String) entry.getValue();
    System.out.println("key:" + key + "---" + "value:" + value);
        }

截取一小部分的结果

key:623---value:623
key:865---value:865
key:624---value:624
key:866---value:866
key:625---value:625
key:867---value:867
key:626---value:626
key:868---value:868
key:627---value:627

一路跟进到最后找到

HashIterator() {
  expectedModCount = modCount;
    Node<K,V>[] t = table;
    current = next = null;
    index = 0;
    if (t != null && size > 0) { // advance to first entry
        do {} while (index < t.length && (next = t[index++]) == null);
    }
}

虽然还是在遍历最初的对象数组,看起来实际上是通过有顺序的数组遍历的,但是当他把next设置为其他对象的时候,最后的顺序就不是按照数组的顺序去取数了,而这个顺序由hash算法后的数值决定。这也就是为什么存进去的顺序和取出来的顺序不相同的原因。


总结

  1. HashMap的内部由一个对象数组存储,但是顺序不由数组决定。
  2. HashMap类似於单链表结构。
  3. HashMap是无序的单链表结构,并且顺序由内置的hash算法决定。

参考文章

浅谈HashMap原理,记录entrySet中的一些疑问

文章中出现的任何错误欢迎指正!共同进步!

最后做个小小广告,有对WEB开发和网络安全感兴趣的,可以加群一起学习和交流!

交流群
QQ:425343603

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