HashMap和ArrayList在Java中都是动态扩容的数据结构,但它们的扩容机制有显著区别:
ArrayList扩容机制
- 初始容量:默认10(无参构造时)
- 扩容时机:当元素数量超过当前容量时
- 扩容策略:
- 新容量 = 旧容量 * 1.5(即增加50%)
- 使用
Arrays.copyOf()
创建新数组并复制数据
- 扩容开销:只需复制数组元素,相对简单
HashMap扩容机制
- 初始容量:默认16(无参构造时)
- 负载因子:默认0.75(当元素数量达到容量*负载因子时触发扩容)
- 扩容时机:当size > capacity * loadFactor时
- 扩容策略:
- 新容量 = 旧容量 * 2(总是翻倍)
- 需要重新计算所有元素的hash值并重新分布(rehash)
- 扩容开销:比ArrayList大得多,因为需要重新计算hash和重新分布节点
主要区别
特性 | ArrayList | HashMap |
---|---|---|
扩容触发条件 | size > capacity | size > capacity*loadFactor |
扩容倍数 | 1.5倍 | 2倍 |
扩容后操作 | 简单数组复制 | 复杂的rehash过程 |
性能影响 | 相对较小 | 相对较大 |
容量要求 | 无特殊要求 | 总是保持为2的幂次方 |
为什么HashMap要翻倍扩容?
HashMap采用2的幂次方容量是为了:
- 优化hash计算:
index = (n - 1) & hash
- 元素分布更均匀,减少哈希冲突
实际应用建议
- 对于ArrayList:如果能预估大小,最好在构造时指定初始容量
- 对于HashMap:如果能预估大小,最好指定初始容量和适当的负载因子
两者扩容都是代价较高的操作,应尽量避免频繁发生。