HashMap 在1.8里处理哈希冲突和性能方面的一些改进

Java 1.8 引入了对 HashMap 的一些重要改进,特别是在处理哈希冲突和性能方面。以下是对 HashMap 1.8 实现逻辑的分析。

1. 数据结构

HashMap 的主要数据结构是数组和链表(或红黑树):

  • 数组:用于存储桶(buckets),每个桶可以包含多个键值对。
  • 链表:在每个桶中,使用链表来存储哈希冲突的键值对。
  • 红黑树当链表的长度超过阈值(默认为 8)且当前容量(即桶的数量)达到一定阈值(默认为 64)时,链表会转换为红黑树,以提高查找效率

2. 重要字段

HashMap 的核心字段包括:

  • Node<K,V>[] table:存储桶的数组。
  • int size:当前映射中键值对的数量。
  • int threshold:桶的阈值,当数组的大小超过这个值时,HashMap 会进行扩容。
  • float loadFactor:负载因子,决定了何时进行扩容,默认值为 0.75。

3. 构造函数

HashMap 提供多个构造函数,允许用户指定初始容量和负载因子。默认情况下,初始容量为 16,负载因子为 0.75。

4. 哈希函数

HashMap 使用 hash(Object key) 方法来计算键的哈希值。它会对键的哈希值进行处理,以减少碰撞的可能性。具体实现如下:

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

这个方法通过 XOR 操作和右移操作来增强哈希值的分布性。

5. 插入元素

插入元素的过程如下:

  1. 计算哈希值:使用 hash() 方法计算键的哈希值。
  2. 确定桶的位置:通过 indexFor(hash, table.length) 方法计算元素应该放置的桶的索引。
  3. 处理冲突
    • 如果桶为空,直接插入。
    • 如果桶不为空,遍历链表检查是否存在相同的键:
      • 如果找到相同的键,更新值。
      • 如果没有找到,插入到链表的末尾。
      • 如果链表长度超过 8且前桶的数量大于等于 64,转换为红黑树。

6. 查找元素

查找元素的过程如下:

  1. 计算哈希值:使用 hash() 方法计算键的哈希值。
  2. 确定桶的位置:通过 indexFor(hash, table.length) 方法计算桶的索引。
  3. 遍历桶
    • 如果桶为空,返回 null。
    • 如果桶中是链表,遍历链表查找键。
    • 如果桶中是红黑树,使用树的查找方法。

7. 扩容

HashMap 中的元素数量超过 threshold 时,会触发扩容。扩容的过程如下:

  1. 新建一个更大的数组:通常是原数组大小的两倍。
  2. 重新计算每个元素的位置:遍历原数组的每个桶,将元素重新插入到新的桶中。
  3. 更新阈值:新的阈值为新数组大小乘以负载因子。

8. 性能优化

  • 链表到红黑树的转换:当链表长度超过 8 时且前桶的数量大于等于 64,链表会转换为红黑树,以提高查找效率,从 O(n) 降低到 O(log n)。
  • 使用 NodeHashMap 1.8 使用 Node 类来表示每个键值对,简化了结构。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值