ArrayList
的自动扩容机制是其功能强大且灵活的特性之一。当向 ArrayList
中添加元素时,如果当前的数组容量不足以容纳新元素,ArrayList
会自动扩展其底层数组的大小。下面是对这个机制的详细说明。
扩容机制的详解
-
初始容量:
ArrayList
默认的初始容量是 10。如果你在创建ArrayList
时没有指定初始大小:ArrayList<String> list = new ArrayList<>();
- 你也可以在构造时指定初始容量:
ArrayList<String> list = new ArrayList<>(20); // 初始容量为 20
-
元素添加过程:
- 当你调用
add()
方法向ArrayList
添加元素时:list.add("element");
- 方法会首先检查当前元素数量(
size
)和底层数组的长度(elementData.length
):if (size == elementData.length) {ensureCapacity(size + 1); // 扩容 }
- 当你调用
-
保证容量:
ensureCapacity(int minCapacity)
方法用于确保ArrayList
能够容纳至少minCapacity
个元素。- 如果元素数量超过当前容量,
ensureCapacity
会执行扩容。
-
扩容算法:
- 在扩容过程中,
ArrayList
通常会将当前容量扩大 1.5 倍:int newCapacity = oldCapacity + (oldCapacity >> 1);
- 这个逻辑的意思是,新的容量等于原容量加上原容量的 50%。例如:
- 如果当前容量是 10,新的容量将是 15。
- 如果当前容量是 15,新的容量将是 22(15 + 7)。
- 在扩容过程中,
-
复制元素:
- 创建新数组后,
ArrayList
会将旧数组中的元素复制到新数组中,通常使用System.arraycopy()
方法:elementData = Arrays.copyOf(elementData, newCapacity);
- 创建新数组后,
自动扩容的示例代码
以下是一个简单示例,说明 ArrayList
如何进行扩容:
import java.util.ArrayList;public class Main {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();// 添加元素,超过默认容量时会自动扩容for (int i = 0; i < 15; i++) {list.add("Element " + i);System.out.println("Added: Element " + i + " | Size: " + list.size() + " | Capacity: " + getCapacity(list));}}// 反射方法,获取 ArrayList 的底层容量(为了测试)private static int getCapacity(ArrayList<?> list) {try {var field = ArrayList.class.getDeclaredField("elementData");field.setAccessible(true);return ((Object[]) field.get(list)).length;} catch (Exception e) {return -1; // 出错时返回-1}}
}
性能影响
-
时间复杂度:虽然在数组满加载时需要重新分配和复制元素,因此
add()
方法在最坏情况下的时间复杂度为O(n)
(n
是当前容纳的元素数),但在平均情况下,它的时间复杂度是O(1)
(均摊的成本)。 -
空间利用率:扩容时会造成一定的空间浪费。因为在不断扩展的过程中,可能会留下不必要的空闲空间。
总结
ArrayList
的自动扩容机制使得它可以动态调整其容量,以适应不断增长的数据集。了解这一机制有助于更好地利用 ArrayList
,选取合适的初始容量并合理管理元素添加,从而提升程序性能。如果你还有其他问题或需要更深入的讨论,请随时问我!