ArrayList的扩容机制
一、初始化机制
- JDK 1.7:
- 饿汉式初始化:使用无参构造方法
new ArrayList()
时,直接创建长度为 10 的Object[] elementData
数组,无论是否立即添加元素 - 缺点:若未立即使用集合,会浪费内存空间。
- 饿汉式初始化:使用无参构造方法
- JDK 1.8:
- 懒汉式初始化:无参构造方法
new ArrayList()
时,初始化一个空数组{}
(DEFAULTCAPACITY_EMPTY_ELEMENTDATA
),容量为 0。第一次调用add()
方法时,才会创建长度为 10 的数组 - 优点:延迟数组创建,节省内存资源,尤其适用于未立即使用的集合场景
- 懒汉式初始化:无参构造方法
二、构造方法行为
- JDK 1.7:
- 所有构造方法(包括无参构造)均直接初始化数组。例如,
new ArrayList()
强制分配容量为 10,new ArrayList(0)
则创建空数组
- 所有构造方法(包括无参构造)均直接初始化数组。例如,
- JDK 1.8:
- 无参构造方法不再预分配空间,仅当显式指定初始容量(如
new ArrayList(10)
)时才会直接初始化数组 - 若传入集合参数(如
new ArrayList<>(existingList)
),则直接复制集合元素的数组,避免冗余扩容
- 无参构造方法不再预分配空间,仅当显式指定初始容量(如
三、扩容机制
- 扩容规则:
- 共同点:当数组容量不足时,JDK 1.7 和 1.8 均按 1.5 倍(即
oldCapacity + (oldCapacity >> 1)
)扩容,并将旧数组元素复制到新数组 - 触发条件:添加元素时,若当前容量不足(
size + 1 > elementData.length
),触发扩容
- 共同点:当数组容量不足时,JDK 1.7 和 1.8 均按 1.5 倍(即
- 性能优化:
- JDK 1.8 在首次调用
add()
时才会初始化数组,避免了无参构造场景下的无效内存占用 - 建议在已知数据规模时使用带参构造方法(如
new ArrayList(100)
),减少扩容次数以提升性能
- JDK 1.8 在首次调用
四、内存与性能对比
<!--br {mso-data-placement:same-cell;}--> td {white-space:nowrap;border:0.5pt solid #dee0e3;font-size:10pt;font-style:normal;font-weight:normal;vertical-align:middle;word-break:normal;word-wrap:normal;}
维度 | JDK 1.7 | JDK 1.8 |
---|---|---|
初始化策略 | 预分配内存(可能浪费资源) | 按需分配内存(节省内存) |
扩容频率 | 可能因预分配容量较高而减少扩容次数 | 首次添加元素必扩容,后续扩容频率相同 |
适用场景 | 需立即添加大量元素的场景 | 内存敏感型场景或延迟初始化需求 |
五、总结与建议
- JDK 1.7:适用于需要快速响应添加操作的场景,但可能因预分配内存导致资源浪费。
- JDK 1.8:通过懒加载优化内存使用,适合不确定初始数据量的场景,但首次添加元素时会有轻微性能损耗
- 最佳实践:
- 预分配容量:若已知数据规模,优先使用带参构造方法指定初始容量。
- 避免频繁扩容:批量添加数据时,提前调用
ensureCapacity()
预扩容
发布评论