下面是 List (以 ArrayList 为例) 和 Map (以 HashMap 为例) 在扩容机制方面的详细对比:

特性 ArrayList(List) HashMap(Map)
核心用途 存储有序的元素列表,允许重复元素。通过索引(0, 1, 2...)快速访问。 存储键值对映射(Key-Value pairs),键不允许重复。通过(Key)快速查找对应的值(Value)。
底层结构 动态数组 (Object[]) 哈希表(数组 + 链表/红黑树)
扩容触发条件 元素数量 (size) >= 内部数组容量(简单地说,数组满了就扩容) 元素数量 (size) >= (容量 * 负载因子) (threshold)(只有当哈希表“装得太满”时才扩容)
扩容条件的控制因素  (固定是容量满了)  (loadFactor 负载因子)
默认初始容量 10 (首次添加元素时) 16
默认负载因子 0.75
扩容比例 约 1.5 倍 (新容量 = 旧容量 + 旧容量 / 2) 2 倍 (新容量 = 旧容量 * 2)
扩容后元素位置变化 不变(元素按原有顺序复制到新数组,索引不变) 通常会改变(需要根据新数组大小重新计算哈希值,进行重新哈希 rehashing)
扩容目的 解决空间不足的问题。 解决哈希冲突过多(负载因子过高)导致性能下降的问题。
扩容开销 主要是 System.arraycopy 拷贝旧数组数据到新数组的时间开销和内存开销。 主要是 rehashing 重新计算所有元素哈希值并重新分配位置的时间开销,以及内存开销。通常比 ArrayList 的 copy 开销更大。
性能影响 扩容时有开销,但扩容后性能恢复 O(1)(按索引访问)。 扩容时有较大开销,但扩容后能将平均性能维持在 O(1)(按 Key 查找)。

核心区别点总结:

  1. 扩容逻辑不同:

    • ArrayList 是一种被动式的扩容,只要空间不够了(size == capacity)就扩容,不管内部元素分布如何。
    • HashMap 是一种阈值驱动的扩容,它引入了负载因子的概念,只有当填充程度(size / capacity)达到某个预设的危险阈值(loadFactor)时才扩容。
  2. 扩容比例不同:

    • ArrayList 每次扩容约 1.5 倍,增长速度相对平缓。
    • HashMap 每次扩容 2 倍,增长速度更快,以迅速降低负载因子。
  3. 扩容后的影响不同:

    • ArrayList 扩容后,元素的逻辑顺序和索引位置不变。
    • HashMap 扩容后,大部分元素都需要重新计算其在新哈希表中的位置,这是一个昂贵的操作。
  4. 设计目标不同:

    • ArrayList 的扩容是为了动态管理连续的存储空间,以适应元素数量的变化。
    • HashMap 的扩容是为了维持哈希表的性能,通过控制负载因子来预防因冲突过多而导致的性能恶化。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐