HashMap源码学习总结

最近发现很多面试都会问及关于HashMap的底层源码,所以简单的了解了一下,现在写一篇总结用以备忘。

  1. HashMap的数据结构为“数组+链表形式”,并且链表为单向链表,如下图(图片来源于网络):
    HashMap数据结构图
  2. 数组的默认大小为static final int DEFAULT_INITIAL_CAPACITY = 1 << 4,即将二进制数字1向左位移四位,得到二进制数字10000,换算成10进制就是16,之所以在源码中采用位移运算,是因为效率高。
  3. 数组的最大长度为static final int MAXIMUM_CAPACITY = 1 << 30
  4. 关于数组扩容的时机,源码中给出了一个因子,static final float DEFAULT_LOAD_FACTOR = 0.75f,这个因子的大小是工程师们通过计算得出的一个最佳的值(可以理解成和黄金比例差不多的东西),当数组的被占用的长度达到“当前长度*因子”时,数组就会进行扩容,并且扩容后的长度为当前长度的二倍。
  5. 为了方便以后说明,现在这里提一下hash()方法:
    static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    ,当key不为null的时候hash()会通过key调用hashCode()方法,得到的值是一个32位的二进制数据并赋予h,然后将h的高16位和低16位进行异或运算得出hash值,也就是数据将在数组中插入的位置,此方法主要是用来获取0-15之间的数 (因为数组默认长度是16)
  6. 当向HashMap中进行put操作时,(如果是第一次,则会进行数组的初始化)首先判断要加入的hash是否存在,若不存在填入数据节点,若存在,则继续判断;当put的key和其hash值与数组里的某个节点数据均相同,则将其覆盖,若hash相同而key不同,则在此hash节点后新增节点(这就是链表的产生),在每次put操作过后都会进行一个数组占用size的判断,若占用量达到条件,则对数组进行扩容if (++size > threshold)
    resize();
  7. 关于数组的扩容机制 resize()方法:当数组长度已经大于最大长度,那么就不管他了;如果当前数组长度大于默认初始长度并且当前长度的二倍小于最大长度,那么就将数组扩大为二倍
    if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
    oldCap >= DEFAULT_INITIAL_CAPACITY)
    newThr = oldThr << 1; // double threshold
    }
  8. 当put将链表的长度大于8时,链表会转为红黑树结构;当remove将红黑树长度小于6时,红黑树会转为链表结构(此举可以提高代码效率)
  9. 数组的大小一直是2的n次方,目的是用来保证数据存入数组位置的分散性,扩容是双倍扩容也是为了保证数组的大小一直为2的n次方
  10. 当数组扩容后,链表的位置要么是在原来的位置,要么是在原来的位置+16后的位置
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值