zoukankan      html  css  js  c++  java
  • HashMap源码调试——认识"put"操作

    前言:通常大家都知道HashMap的底层数据结构为数组加链表的形式,但其put操作具体是怎样执行的呢,本文通过调试HashMap的源码来阐述这一问题。

    注:jdk版本:jdk1.7.0_51


    1.put源码

     1 public V put(K key, V value) {
     2         if (table == EMPTY_TABLE) {
     3             inflateTable(threshold);
     4         }
     5         if (key == null)
     6             return putForNullKey(value);
     7         int hash = hash(key);
     8         int i = indexFor(hash, table.length);
     9         for (Entry<K,V> e = table[i]; e != null; e = e.next) {
    10             Object k;
    11             if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
    12                 V oldValue = e.value;
    13                 e.value = value;
    14                 e.recordAccess(this);
    15                 return oldValue;
    16             }
    17         }
    18 
    19         modCount++;
    20         addEntry(hash, key, value, i);
    21         return null;
    22     }

    下面通过对源码调试具体说明put操作的流程。

    2.具体调试过程

     1 public class CodeTest04
     2 {
     3     public static void main(String[] args)
     4     {
     5         String keyAa = "Aa";
     6         String keyBB = "BB";
     7 
     8         System.out.println("keyAa hashCode=" + keyAa.hashCode());
     9         System.out.println("keyBB hashCode=" + keyBB.hashCode());
    10 
    11         HashMap<String, String> hashMap = new HashMap<String, String>();
    12 
    13         hashMap.put(keyAa, "abc");
    14 //        hashMap.put(keyBB, "abc");
    15         hashMap.put(keyAa, "cba");
    16         hashMap.put(keyAa,"def");
    17         
    18         System.out.println(hashMap);
    19 
    20     }
    21 }

    说明:

    不同内容的字符串,其hashCode是可能相等的。如字符串“Aa”和“BB”的hashCode相等(都是2112)。

    ②当执行上述代码13行和15、16行的时候,结果如下:

    ③当执行上述代码13行和14行时,结果如下:

    通过上述结果,可得出如下结论:

    ①在key的hashCode相等,且key也相同的情况下,HashMap在执行put操作的时候,会进行覆盖操作,新值将覆盖旧值,所以最后输出为"{Aa=def}"。

    ②在key的hashCode相等,但key不相同(如"Aa"与"BB")的情况下,HashMap在执行put操作的时候,就会进行链表式存储,并且采用的是头插法,即新值处于链表头,最开始的值处于链表尾

    #1.对于第一个结论,通过下面这段源码可以很清晰的了解其流程:

    #2.对于第二个结果,key的hashCode相等,但key不同的情况,通过调试描述put的过程。

    通过debug可以非常清晰的看出:当前hashmap中存在一对键值{"Aa"->"abc"},其key的hash值为2112,在put("BB","abc")的时候,发现其hash值也是2112,出现上文中描述的情况(key的hashCode值相等,当key的内容不同),因此会直接跳转。

    注意i的值,这里的i表示put元素在hashmap底层数据结构中的索引值(可简单想象成元素在数组上的索引),因为"Aa"与"BB"的hashCode值相同,因此两次i的值都是4。我们进入addEntry函数。

    由于我们这里不需要扩容,因此会创建新的元素,注意此时桶的index为4,但是当前位置上已经存在"Aa"的键值对了,进入该函数。

    这里可以清晰的看出,会取出之前bucketIndex=4上的键值对,也就是{"Aa"->"abc"},然后new一个Entry。

    关键过程:把当前bucketIndex=4的值替换成了{"BB"->"abc"},并将其next的值赋值为{"Aa"->"abc"},这里就完成了头插法

    总结

    HashMap在进行put操作时,会有如下操作:

    1)在key的hashCode相等,且key的内容也相同的情况下(两次"Aa"),就会对value值进行覆盖

    2)在key的hashCode相等,但key的内容不相同的情况下("Aa","BB"),会进行链式存储,并且是头插法,新加的值("BB")在链表头,最开始("Aa")的值在链表尾。

    3)在key的hashCode不相等的情况,直接进行散列存储。

    4)从上述调试过程也发现,HashMap主要是以key为主,value相当于key的一个附属值,因为value随key走的。


    by Shawn Chen,2018.6.8日,晚。

  • 相关阅读:
    OpenCV3 for python3 学习笔记1
    OpenCV3 for python3 学习笔记2
    python3 requests获取某网站折线图上数据
    python BeautifulSoup的简单使用
    Python爬虫之Cookie和Session(转载)
    python 获取前一天或前N天的日期
    python 进程池pool简单使用
    GitHub for Windows简单使用
    Windows上的git、github部署及基本使用方法
    python unknown error: DevToolsActivePort file doesn't exist 问题解决
  • 原文地址:https://www.cnblogs.com/developer_chan/p/9153490.html
Copyright © 2011-2022 走看看