下面是 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编程工具,助力开发者即刻编程。

更多推荐