Java 中 HashMap 与 HashSet 底层实现原理(配套习题)

⭐️前面的话⭐️

HashMap 是 Java 集合框架中 Map 容器的一个实现类,用于存储键值对(key - value)。在 JDK 7 中,其底层采用数组 + 链表实现;在 JDK 8 中,采用数组 + 链表 + 红黑树实现。所有的 key 构成一个 Set 集合,key 无序且不能重复,同时 HashMap 支持存储 key/value 为 null 的元素。

📒博客主页:未见花闻的博客主页
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
📌本文由未见花闻原创,CSDN首发!
📆首发时间:🌴2025年5月5日🌴
✉️坚持和努力一定能换来诗与远方!
💭推荐书籍:📚《无》
💬参考在线编程网站:🌐牛客网🌐力扣🌐acwing
博主的码云gitee,平常博主写的程序代码都在里面。
博主的github,平常博主写的程序代码都在里面。
🍭作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!



封面区


一、知识点讲解

1.1 HashMap 基本概念

HashMap 是 Java 集合框架中 Map 容器的一个实现类,用于存储键值对(key - value)。在 JDK 7 中,其底层采用数组 + 链表实现;在 JDK 8 中,采用数组 + 链表 + 红黑树实现。所有的 key 构成一个 Set 集合,key 无序且不能重复,同时 HashMap 支持存储 key/value 为 null 的元素。

1.2 HashMap 的属性

  • 默认容量DEFAULT_INITIAL_CAPACITY = 1 << 4,即 16,且必须是 2 的幂。
  • 最大容量MAXIMUM_CAPACITY = 1 << 30,即 2 30 2^{30} 230
  • 默认负载因子DEFAULT_LOAD_FACTOR = 0.75f
  • 链表树化阈值TREEIFY_THRESHOLD = 8,当数组长度大于 64 且链表长度超过 8 时,链表转换为红黑树。
  • 红黑树链表化阈值UNTREEIFY_THRESHOLD = 6,当红黑树结点个数小于 6 时,红黑树转换为链表。
  • 底层数组transient Node<K,V>[] table,是一个链表数组。
  • 元素个数阈值threshold = capacity * loadFactor,当 size 大于 threshold 时会执行 resize 操作。

1.3 HashMap 的构造方法

  • 无参构造方法:默认容量为 16,但此时不会申请数组空间。
public HashMap() {
   
   
    this.loadFactor = DEFAULT_LOAD_FACTOR; 
}
  • 指定容量的构造方法:取大于或等于指定容量的最接近的 2 次幂数,同样不立即申请数组空间。
public HashMap(int initialCapacity) {
   
   
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
  • 指定容量和负载因子的构造方法tableSizeFor(initialCapacity) 生成比 initialCapacity 大并最接近的 2 次幂。
public HashMap(int initialCapacity, float loadFactor) {
   
   
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
    this.loadFactor = loadFactor;
    this.threshold = tableSizeFor(initialCapacity);
}
  • 根据其他 Map 对象构造:若传入的参数有元素,则申请数组空间,否则不申请。
public HashMap(Map<? extends K, ? extends V> m) {
   
   
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    putMapEntries(m, false);
}

1.4 HashMap 开辟数组的时机

真正为数组分配内存是在第一次 put 操作时。

public V put(K key, V value) {
   
   
    return putVal(hash(key), key, value, false, true);
}

1.5 HashMap 中的 put 操作

  • 首次扩容:若数组为空,则进行第一次扩容(resize),申请默认容量大小为 16 的数组。
  • 插入数据步骤
    1. 通过 hash() 方法计算索引,找到键值对在数组中的位置。
    2. 插入数据:
      • 若当前位置元素为空,直接插入。
      • 若当前位置元素非空,遍历链表或红黑树,若 key 已存在,则覆盖其 value。
      • 若当前位置元素非空,遍历链表或红黑树,若 ke
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

未见花闻

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

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

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

打赏作者

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

抵扣说明:

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

余额充值