源码-JDK1.8HashMap扩容方法resize()解析

1、准备知识

  • HashMap的底层数据结构

    Java语言的基本数据结构可以分为两种,一种是数组,另一种的模拟指针/引用,Java语言中涉及到的数据结构都是这两种的扩充。JDK1.8之前HashMap是数组+链表结合的链表散列。JDK1.8在解决哈希冲突上发生了变化,当链表长度大于阈值/默认8的时候,会将链表转化为红黑树,减少搜索时间。

在这里插入图片描述

  • hash算法

    我们希望HashMap的元素位置尽量分散,最好是每个位置只有一个元素,这样用hash算法求得该位置后可以直接返回结果,不用再遍历链表/红黑树。

    HashMap通过Key的hashCode经过扰动函数(就是hash方法)处理后得到hash值,然后在公式(n-1)& hash (/n是数组长度)判断当前元素的位置是否已存在元素,若已存在则判断新加入的元素和已存在的是否相同,相同则覆盖,不相同则拉链法解决冲突。

    //扰动函数 == hash方法
    /*JDK1.7
    此函数可确保仅在以下方面不同的hashCode每个位位置的恒定倍数有界碰撞次数(默认负荷系数下约为8)。
    */
    static int hash(int h){
         
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
     
    /*JDK1.8的hash方法比JDK1.7的更加简化,JDK1.7的扰动需要4次,JDK1.8的仅需1次*/
    static int hash(Object key){
         
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    
    • 拉链法:将链表和数组相结合。也就是说创建⼀个链表数组,数组中每⼀格就是⼀个链表。若遇到哈希冲突,则将冲突的值加到链表中即可。下次查询的时候,需要遍历这个链表找到元素,减慢了查询效率。

    • ->所有,在存储大规模的数据时,预先指定HashMap的大小为2的幂次方

      int capacity = 1;
      while(capacity < initialCapacity){
             
          capacity <<= 1;//扩大两倍
      }
      

    2、HashMap的resize()方法介绍

    • 当HashMap中的元素增多时,发生哈希冲突的几率就越来越高,这时候为了提高查询的效率,需要对数组大小进行扩容。

    • 当数组的元素规模 > 数组大小 * loadFactory时进行扩容,loadFactory默认是0.75

      ... map = new HashMap<>(c, loadFactor)//HashMap提供了以上有参构造方法
          //initialCapacity是HashMap数组的初始容量
          //loadFactor是加载因子
      
    • 什么时候进行resize?1、初始化table的时候 2、数组元素size超出threshold = map.size() * loadFactory

      直接扩容 原数组的2倍大小

    • 节点在转移的过程中是一个个节点复制还是一串一串的转移?从源码中我们可以看出,扩容时是先找到拆分后处于同一个桶的节点,将这些节点连接好,然后把头节点存入桶中即可

    • 话不多说,上源码

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值