典型回答
ArrayList 在添加元素时,会自动进行扩容操作,它的执行步骤如下:
- 当 ArrayList 的内部数组空间不足以容纳新增的元素时,会触发扩容机制。
- ArrayList 会创建一个新的更大的数组,通常是当前数组长度的 1.5倍 (可以通过 ensureCapacity 方法手动调整容量)。
- 然后,ArrayList 会将原数组中的元素逐个复制到新数组中,以保持元素的顺序。
- 扩容完成后,修改 ArrayList 变量的引用为新数组的引用。
所以,当需要添加大量元素时,可以考虑在创建 ArrayList 时直接指定初始容量,这样可以减少扩容次数,提高效率。
使用 ensureCapacity 调整容量的代码如下:
import java.lang.reflect.Field;
import java.util.ArrayList;public class ArrayListCapacityDemo {public static void main(String[] args) {ArrayList<Integer> numbers = new ArrayList<>(10);numbers.add(5);numbers.add(10);numbers.add(15);System.out.println("当前实际容量: " + numbers.size());System.out.println("当前总容量: " + getArrayListCapacity(numbers));// 使用 ensureCapacity 方法增加容量numbers.ensureCapacity(20);System.out.println("扩容后的实际容量: " + numbers.size());System.out.println("扩容后的总容量: " + getArrayListCapacity(numbers));try {// 通过反射获取 ArrayList 总容量// JDK 8+ 需要设置以下 JVM 参数:// --add-opens java.base/java.lang=ALL-UNNAMED// --add-opens java.base/java.util=ALL-UNNAMED// --add-opens java.base/java.nio=ALL-UNNAMED// --add-opens java.base/sun.nio.ch=ALL-UNNAMEDSystem.out.println("通过反射获取 ArrayList 总容量: " + getArrayListCapacityReflection(numbers));} catch (NoSuchFieldException | IllegalAccessException e) {e.printStackTrace();}}private static int getArrayListCapacity(ArrayList<?> arrayList) {return arrayList.toArray().length;}private static int getArrayListCapacityReflection(ArrayList<?> arrayList) throws NoSuchFieldException, IllegalAccessException {Field dataField = ArrayList.class.getDeclaredField("elementData");dataField.setAccessible(true);Object[] elementData = (Object[]) dataField.get(arrayList);return elementData.length;}
}
以上程序的运行结果如下: