面试 Java 基础八股文十问十答第三十期

发布于:2024-05-07 ⋅ 阅读:(29) ⋅ 点赞:(0)

面试 Java 基础八股文十问十答第三十期

作者:程序员小白条个人博客

相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新!

⭐点赞⭐收藏⭐不迷路!⭐

1)HashMap 和 HashTable 的区别

  • 线程安全性: HashMap 是非线程安全的,而 HashTable 是线程安全的,所有方法都被 synchronized 关键字修饰。
  • null 键值: HashMap 允许键和值都为 null,而 HashTable 不允许键或值为 null,否则会抛出 NullPointerException。
  • 性能: 由于 HashTable 的方法都是同步的,所以在单线程环境下性能通常比 HashMap 差。

2)HashSet 和 HashMap 的区别

  • 存储方式: HashSet 是基于 HashMap 实现的,它只存储键而没有值,实际上是通过 HashMap 的键来存储元素的。
  • 元素唯一性: HashSet 用于存储不重复的元素,即不允许重复元素存在;而 HashMap 存储键值对,键不能重复,但值可以重复。

3)HashMap 的实现原理

HashMap 是基于哈希表实现的,它的实现原理主要包括以下几点:

  • 哈希函数: HashMap 使用哈希函数将键映射到哈希表的索引位置。这个哈希函数通常会将键的哈希码进行处理,以保证分布均匀,减少哈希冲突的概率。
  • 数组 + 链表 / 红黑树: HashMap 内部维护了一个数组,每个数组元素称为桶(bucket)。当发生哈希冲突时,即多个键映射到同一个桶上时,HashMap 使用链表或者红黑树来存储具有相同哈希码的键值对。在 JDK 8 中,当链表长度超过一定阈值时,链表会转换为红黑树,以提高查找效率。
  • 扩容与重新哈希: 当 HashMap 中的元素个数超过数组容量乘以负载因子时,就会触发扩容操作。扩容操作会创建一个新的更大的数组,并将所有键值对重新哈希到新的数组中,以保持性能稳定。
  • 迭代顺序: HashMap 中的元素没有固定的顺序,迭代顺序由哈希桶的顺序和哈希碰撞解决方法决定,因此不能保证元素的顺序性。

4)HashMap 的扩容机制

HashMap 的扩容机制是在达到一定负载因子(Load Factor)时进行的,负载因子是指哈希表中的元素数量与桶的数量的比值。当负载因子超过阈值时,HashMap 会自动进行扩容操作。扩容过程包括以下几个步骤:

  1. 创建一个新的两倍大小的数组。
  2. 将原数组中的所有键值对重新计算哈希值,并根据新的数组大小重新分配到新的桶中。
  3. 将原数组中的每个桶中的键值对转移到新数组中的对应位置。
  4. 最后,将原数组引用指向新数组,完成扩容操作。

5)HashMap 扩容是 2 的 n 次方倍的原因

HashMap 扩容为 2 的 n 次方倍的大小有助于提高哈希表的性能和均匀性。当扩容因子为 2 的 n 次方倍时,通过与运算(&)可以实现快速定位元素的新位置,而不需要重新计算哈希值。这样可以提高扩容时的效率,减少元素重新分布的成本。同时,使用 2 的 n 次方倍的大小也可以保证桶的数量总是增加或减少一倍,使得哈希表的分布更加均匀。

6)HashMap 默认扩容负载因子为 0.75 的原因

HashMap 的默认扩容负载因子为 0.75 是一种折中考虑。较低的负载因子会导致哈希表频繁扩容,增加空间浪费和性能损耗;而较高的负载因子会导致哈希碰撞的概率增加,影响查找、插入和删除操作的性能。经过实验和分析,0.75 的负载因子被认为是一个比较合理的值,可以在空间利用率和性能之间取得较好的平衡。

7)设计一个 HashMap 的考虑因素

  • 哈希函数设计: 设计一个好的哈希函数是 HashMap 的核心,它需要将键尽可能均匀地映射到哈希表的不同位置,以减少哈希冲突的概率。
  • 解决哈希冲突: 考虑使用开放寻址法或链地址法等方式来解决哈希冲突,可以选择适合场景的冲突解决方法。
  • 负载因子与扩容策略: 设计合适的负载因子和扩容策略,以平衡空间利用率和性能,并避免频繁的扩容操作。
  • 线程安全性: 根据使用场景考虑是否需要支持线程安全的 HashMap,可以选择使用同步机制或者使用 ConcurrentHashMap 等线程安全的替代实现。
  • 性能优化: 考虑如何优化 HashMap 的性能,包括优化哈希函数、优化扩容策略、优化冲突解决方法等。

8)JDK 1.8 对 HashMap 做红黑树改动的原因

JDK 1.8 对 HashMap 做红黑树改动的原因是为了解决在哈希碰撞严重时,链表过长导致的性能问题。通过将链表转换为红黑树,可以提高查找、插入和删除操作的性能,尤其是在元素数量较大、哈希冲突严重的情况下。

9)JDK 1.8 对 HashMap 的其他改动

除了引入红黑树以优化性能外,JDK 1.8 对 HashMap 还做了一些其他改动,包括:

  • 优化了哈希函数: JDK 1.8 对哈希函数进行了优化,提高了哈希值的均匀性,减少了哈希碰撞的概率。
  • 优化了扩容策略: JDK 1.8 对扩容策略进行了优化,使得扩容操作更加高效,减少了重新哈希的次数。
  • 优化了迭代顺序: JDK 1.8 对 HashMap 的迭代顺序进行了优化,使得迭代时元素的顺序更加可预测和稳定。

10)LinkedHashMap 的了解

LinkedHashMap 是 Java 中的一个具有可预测迭代顺序的 Map 实现。它除了具备 HashMap 的功能外,还维护了一个双向链表来记录插入顺序或访问顺序,因此可以保证迭代顺序与插入顺序或访问顺序一致。LinkedHashMap 在需要有序遍历 Map 中的元素时非常有用,例如 LRU(Least Recently Used)缓存的实现。

开源项目地址:https://gitee.com/falle22222n-leaves/vue_-book-manage-system

前后端总计已经 1300+ Star,2 W+ 访问!

⭐点赞⭐收藏⭐不迷路!⭐