HashMap的详细介绍(3)

HashMap的详细介绍

—–本文只针对1.7版本的HashMap所讲解.

通过前两节课的学习,我们知道了HashMap的构造过程,以及涉及到的几个问题,今天我们来详细学习一下HashMap的put方法的详细过程,在讲解过程中,我们解决一下第二章预留的一些问题。刚来的同学可以先看看
HashMap的详细介绍(1)
HashMap的详细介绍(2)
好了,现在我们开始讲解今天学的内容了,同学们,抓紧,开车了,看代码:

    public V put(K key, V value) {
        //这里是判断数组是否初始化,没有初始化进行初始化
        //不懂得同学,第一章有详细介绍
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        //如果key为null,则进入次方法,进行添加,然后返回
        if (key == null)
            return putForNullKey(value);
        //这里是进行对key进行hash生成hash码,第二章详细介绍过了
        int hash = hash(key);
        //这里是对生成的hash进行定位,从而得到添加位置
        int i = indexFor(hash, table.length);
        //判断生成的位置是否有值,如果有值,在进行key比较,key也相同,则进行覆盖操作,然后返回旧值
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
          //这个是记录我们对HashMap操作的次数,但是我们可以看见,
        //在1.7的时候,如果我们只是修改数据,它不会执行到这里,这里也就不能自增
        modCount++;
        //如果key不为null,key也不重复,则进行下面的添加操作
        addEntry(hash, key, value, i);
        return null;
    }

我们现在针对key为null的的条件来进行分析,看代码:

     private V putForNullKey(V value) {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;     
        addEntry(0, null, value, 0);
        return null;
    }

putForNullKey这个方法有一个参数,就是我们put的时候传入的value,这里它获取了数组的第0位,然后判断它是否为null,如果不为null就进入循环去判断key是否为null,如果为null,就会去覆盖当前数组0位置元素,如果不为null ,则进入addEntry方法,它传入4个参数,
我们跟踪进去看看:

    //参数1:hash值,参数2:put的key,参数3:put的value,参数4:通过hash值生成的位置
    void addEntry(int hash, K key, V value, int bucketIndex) {
        //这里判断是否需要扩容
        if ((size >= threshold) && (null != table[bucketIndex])) {
            //进行扩容
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }
        //如果不需要扩容,直接进入createEntry
        createEntry(hash, key, value, bucketIndex);
    }

参数1:hash值,参数2:put的key,参数3:put的value,参数4:通过hash值生成的位置,我们看到进入这个方法,先会判断该数组是否需要扩容,如果不需要,则直接进入createEntry,参数仍然是这4个参数,我们继续跟踪代码:

    void createEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<>(hash, key, value, e);
        size++;
    }

我们可以看到,它先把当前位置的元素,赋值给了e这个变量,然后新建了一个Entry对象,我们看到这里面有四个参数,一个为hash值,一个为key,一个为value,还有一个就是我们上面赋值的e这个变量,我们都知道HashMap的底层是数组加单向链表,这里就形成了一个链表,如果我们e变量不为null则这里就形成了一个链表结构,然后把新建出来的对象放入table[bucketIndex]也就是数组的0的位置,因为bucketIndex为0,所以我们这里有几个重要的知识需要说明。
一:put一个key为null的元素,它会直接把放入数组0的位置,而不会去计算hash值和生成位置。
二:当我们0的位置不为null则会出现链表,它把新的数据放在最前,旧的数据放在最后,类是于栈的结构,先进后出.

通过上面的学习,我们就能掌握当key为null的时候HashMap的详细执行流程,当我们key不为null的时候呢?又会进行那些操作?返回到上面我们来详细看看,

     public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
         //当我们key为null的时候,我们上面已详细介绍我们
         //来看看不为null的时候
        if (key == null)
            return putForNullKey(value);
         //根据key生成hash码
        int hash = hash(key);
     //对hash码进行运算,生成位置,第一,二章,有详细介绍
        //这里就不介绍了
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

我们可以看到不为null,它先会生成hash码,然后对hash码运算生成位置,同样的,它会先去判断该位置是否为null不为null则进行判断key是否相等,相等则覆盖,返回旧元素,如果不为null 则进入addEntry方法,然后后面的操作几乎和key为null大致一样,这里就不多说了。

我们可以发现key不为null只比key为null多了两个步骤,一个就是通过key来生成hash码,然后在通过hash码来生成对应的位置,其他的操作都是一样的。

好了,今天的课程就到这里,今天的内容,比较简单。下章我们将 继续讲解get方法的详细介绍,今天内容就到这里,下期再见。

书山有路勤为径,学海无涯苦作舟。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值