hashMap1.7put方法源码剖析

hashMap1.7

底层是Entry对象的列表和table数组

Entry对象的属性

final K key;

       V value;

       Entry<K,V> next;

       int hash;

1 开始的时候table数组为空 没有初始化  开始初始化

下列初始时化方法中capacity字段值为16默认的,toSize值 为16 通过roundUpToPowerOf2()方法计算出来的。roundUpToPowerOf2方法 计算出来的值都是大于等于toSize2的幂次方数 例如3-164-1615-16 17-32,32-32,33-64

2 put方法中key为null时 将为null时封装的Entry对象放在table数组的首位或首位的链表元素上 addEntry方法就是table数组中保存数据的 后续在分析

3 put的key不为空时有int hash = hash(key)计算出keyhash值,根据hash值计算table数组的下标

 这就是为啥容量计算时有这规律(roundUpToPowerOf2方法 计算出来的值都是大于等于toSize2的幂次方数)  hash值与上数组长度减一

4 put 时根据key的hash值计算出下标 ,根据下标找到table数组中的链表元素 并遍历链表节点,根据key的值和hash值判断是否有相等的(e.hash == hash && ((k = e.key) == key || key.equals(k)) ,如有 将对应的value值被新的覆盖,将老的value值返回

5 如果链表中没有相同key的元素,那么就作为新值进行添加,

  1. 如果是第一次添加,该图的if里面不会执行,里面执行的是扩容逻辑,后续分析

  1. 下图方法是具体的添加元素的的逻辑,方法参数 hash 新增key的hash值 、key和value就是新值、bucketIndex 根据hash值计算出的table下标。根据下标获取元素,此元素也是一个链表的头节点,图中e 就是头节点的引用。 new Entry<>(hash, key, value, e)这一行是创建新节点,并将取得的头节点e赋值给新节点的next属性上,然后将新节点赋值给table表上,新节点就成了对应table数组中的头节点。

6 扩容map中元素数量size大于等于threshold(table数组长度X0.75 (加载因子)),并且根据新增key的hash值计算出的下标对应的table元素不为空。

扩容时新建table数组并且长度是老数组的2倍(2*table.length),newTable就是新的数组

 下图是真正的扩容方法,遍历老table数组的链表和遍历链表上的节点,每个节点的hash值不变,然后根据hash值重新计算节点迁移到新table上的下标。有两个规律

  1. 计算出的下标要么为原来老数组中的下标值  ,要么为老数组的下标值加上老数组的长度。例如原数组长度为3,扩容新数组长度为6,某个元素的在老数组中下标为2那么在新数组中下标可能为2可能为2+3(老数组长度)
  2. 链表的顺序  老新数组是相反的

顺序分析

e=1  e.next=2 next=2 newTable[i]=null

e.next=null,newTable[i]=1 e=2  此时链表元素第一个节点为1

e=2  e.next=3 next=3 newTable[i]=2

e.next=3 newTable[i]=2 e=3    此时链表元素第一个节点是2 第二个节点是1

e=3  e.next=null next=null newTable[i]=null

e.next=null newTable[i]=3 e=null  此时链表元素第一个节点是3 第二个节点是2 第三个节点是1

样例代码 放数据 和扩容

package test;

public class Test {

    public static void main(String[] args) {

       Entry[] table =new Entry[10];

       Entry[] newTable =new Entry[20];

        Entry e1 = table[0];

         table[0] = new Entry("3", "3", e1);

          e1 = table[0];

         table[0] = new Entry("2", "2", e1);

         e1 = table[0];

         table[0] = new Entry("1", "1", e1);

         for (Entry e : table) {

                while(null != e) {

                    Entry next = e.next;

                    e.next = newTable[1];

                    newTable[1] = e;

                    e = next;

                }

            }

         System.out.println(newTable);

      

      

    }

   

    static class Entry{

       String key;

       String value;

       Entry next;

      

       public Entry(String key,String value,Entry entry){

           this.key=key;

           this.value=value;

           this.next=entry;

       }

      

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值