Java 集合探秘:ArrayList 与 HashMap 扩容策略的异同点详解
·
下面是 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 查找)。 |
核心区别点总结:
-
扩容逻辑不同:
ArrayList是一种被动式的扩容,只要空间不够了(size == capacity)就扩容,不管内部元素分布如何。HashMap是一种阈值驱动的扩容,它引入了负载因子的概念,只有当填充程度(size / capacity)达到某个预设的危险阈值(loadFactor)时才扩容。
-
扩容比例不同:
ArrayList每次扩容约 1.5 倍,增长速度相对平缓。HashMap每次扩容 2 倍,增长速度更快,以迅速降低负载因子。
-
扩容后的影响不同:
ArrayList扩容后,元素的逻辑顺序和索引位置不变。HashMap扩容后,大部分元素都需要重新计算其在新哈希表中的位置,这是一个昂贵的操作。
-
设计目标不同:
ArrayList的扩容是为了动态管理连续的存储空间,以适应元素数量的变化。HashMap的扩容是为了维持哈希表的性能,通过控制负载因子来预防因冲突过多而导致的性能恶化。
更多推荐




所有评论(0)