HashMap 原理

  • 在 JDK 1.7 中,HashMap 采用数组+链表的方式实现
  • 在 JDK 1.8 中,HashMap 采用数组+链表 / 红黑树实现
Entry[] table=new Entry[capacity];

基础变量

  • DEFAULT_INITIAL_CAPACITY(Table 数组的初始大小):1 << 4,这里需要是 2 的 n 次方,数组扩容的时候也是每次扩容 2 倍,根本原因是在计算哈希散列时,会使用下面的公式
    • hashCode 的高 16 位和低 16 位进行异或运算,避免只使用低位的情况
    • n - 1 & hashCode 可以将哈希散列均匀散布到 Table 数组中
    • static final int hash(Object key) {
          int h;
          return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
      }
      
      tab[i = (n - 1) & hash]
      
      
  • MAXIMUM_CAPACITY(Table 数组的最大长度):1<<30 = 1073741824
  • DEFAULT_LOAD_FACTOR(负载因子):默认值为 0.75。当元素的总个数 > 当前数组的长度 * 负载因子时,数组会扩容为原来的两倍
  • TREEIFY_THRESHOLD(树化阈值):默认值为 8,当一个 Table 节点下的 Entry 个数大于 8 时,会将链表转换成为红黑树
  • UNTREEIFY_THRESHOLD(链化阈值):默认值为 6,当一个 Table 节点下的 Entry 个数小于 6 时,会将红黑树转化成为链表
  • MIN_TREEIFY_CAPACITY(最小树化阈值)= 64,当 Table 数组元素超过该值,才会进行树化(防止前期阶段频繁扩容和树化过程冲突)

问题一:Table 数组可以替换为 LinkedList 或者 ArrayList 吗?

  • 由于通过哈希散列值可以快速定位数组元素,而 LinkedList 内部通过链表维护,效率较低
  • ArrayList 底层采用数组实现,但是扩容时会扩展 1.5 倍,而 Table 数组为了哈希散列更均匀,需要扩容 2 倍

问题二:简单说一下 HashMap 的 put 元素的过程吗?

  1. 通过对 key 做 hash 运算,计算 index
  2. 如果没碰撞,进行扩容检测,并直接放到 bucket ⾥
  3. 如果碰撞了,以链表的形式存在 buckets 后,如果碰撞导致链表过⻓(⼤于等于TREEIFY_THRESHOLD),就把链表转换成红⿊树
  4. 如果节点已经存在就替换原有的 value

问题三:简单说一下 HashMap 的 get 元素的过程吗?

  1. 通过对 key 做 hash 运算,计算 index
  2. 如果在 bucket ⾥的第⼀个节点⾥直接命中,则直接返回
  3. 如果有冲突,则通过 key 去查找对应的 Entry,若为树,查找效率为 O(logn),若为链表,查找效率为 O(n)

String.hashcode()

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

问题四:知道 JDK1.8 中 HashMap 改了什么吗?

  1. 由数组+链表的结构改为数组+链表+红⿊树
  2. 优化了⾼位运算的hash算法

注意事项

  • HashMap 扩容是一个特别消耗内存的操作,所以尽量在 HashMap 初始化的时候预估一个大致的数值,避免 Map 进行频繁的扩容
  • 负载因子是可以修改的,也可以大于 1,但是建议不要轻易修改,除非情况非常特殊
  • HashMap 是线程不安全的,不要在并发的环境中同时操作 HashMap,建议使用ConcurrentHashMap
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

little-sparrow

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值