ArrayList 模拟手动数组扩容
·
用 ArrayList 模拟手动数组扩容(底层原理复刻)
思路说明
ArrayList 底层是 Object[],核心扩容逻辑:
- 初始空数组,添加元素时判断容量是否足够
- 不够则新建1.5倍容量的新数组
- 通过数组拷贝
System.arraycopy把旧数据迁移到新数组 - 替换底层数组引用
下面自己手写简易动态数组,模仿 ArrayList 扩容逻辑,不直接调用原生 ArrayList,展示扩容底层实现。
完整代码
public class MyArrayList<E> {
// 底层存储数组
private Object[] elementData;
// 当前元素个数
private int size;
// 默认初始容量
private static final int DEFAULT_CAPACITY = 10;
// 空数组常量
private static final Object[] EMPTY_ELEMENTDATA = {};
// 无参构造,初始为空数组
public MyArrayList() {
elementData = EMPTY_ELEMENTDATA;
}
// 添加元素(核心扩容逻辑在这里)
public boolean add(E e) {
// 1. 判断是否需要扩容
ensureCapacityInternal(size + 1);
// 2. 存入元素
elementData[size++] = e;
return true;
}
// 确保容量足够,不足则扩容
private void ensureCapacityInternal(int minCapacity) {
// 如果是空数组,第一次添加直接扩容到默认容量10
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
// 当前数组容量
int oldCapacity = elementData.length;
// 需要扩容
if (minCapacity > oldCapacity) {
grow(minCapacity);
}
}
// 真正扩容方法:新容量 = 旧容量 * 1.5
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// 扩容1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 若1.5倍还是不够,直接使用需要的最小容量
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
// 数组拷贝,生成新数组
elementData = copyOf(elementData, newCapacity);
}
// 模拟 Arrays.copyOf 数组复制
private Object[] copyOf(Object[] oldArr, int newLen) {
Object[] newArr = new Object[newLen];
// 复制旧数组所有元素到新数组
System.arraycopy(oldArr, 0, newArr, 0, oldArr.length);
return newArr;
}
// 根据下标获取元素
@SuppressWarnings("unchecked")
public E get(int index) {
checkIndex(index);
return (E) elementData[index];
}
// 校验下标
private void checkIndex(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("下标越界:" + index);
}
}
// 获取当前元素数量
public int size() {
return size;
}
// 打印所有元素
public void printAll() {
for (int i = 0; i < size; i++) {
System.out.print(elementData[i] + " ");
}
System.out.println();
}
// 测试主方法
public static void main(String[] args) {
MyArrayList<Integer> list = new MyArrayList<>();
// 添加15个元素,触发扩容(初始10,加到第11个时扩容到15)
for (int i = 1; i <= 15; i++) {
list.add(i);
System.out.println("添加第" + i + "个元素,当前元素总数:" + list.size());
}
System.out.print("集合所有元素:");
list.printAll();
System.out.println("下标5的元素:" + list.get(5));
}
}
运行结果说明
- 前10个元素:底层数组长度=10,不扩容
- 添加第11个元素时:
minCapacity=11,旧容量10不足,触发扩容- 新容量 = 10 + 10/2 = 15
- 创建长度15的新数组,复制旧数据
- 最多存15个元素,不会再次扩容,直到超过15个才会再次1.5倍扩容
如果要求:直接使用原生 ArrayList 演示扩容现象
原生 ArrayList 无法直接获取底层数组长度,可通过反射查看容量,代码:
import java.util.ArrayList;
import java.lang.reflect.Field;
public class ArrayListExpandDemo {
public static void main(String[] args) throws Exception {
ArrayList<Integer> list = new ArrayList<>();
// 反射获取底层数组 elementData
Field field = ArrayList.class.getDeclaredField("elementData");
field.setAccessible(true);
for (int i = 1; i <= 12; i++) {
list.add(i);
Object[] arr = (Object[]) field.get(list);
System.out.println("添加" + i + ",数组容量:" + arr.length + ",元素个数size:" + list.size());
}
}
}
输出:
添加1,数组容量:10,元素个数size:1
...
添加10,数组容量:10,元素个数size:10
添加11,数组容量:15,元素个数size:11
添加12,数组容量:15,元素个数size:12
直观看到:存满10个后,第11个元素触发1.5倍扩容到15。
核心扩容关键点总结
- 扩容倍数:
oldCapacity + oldCapacity >> 1= 原容量 * 1.5 - 扩容本质:新建更大数组 +
System.arraycopy拷贝数据 - 空集合第一次add,直接分配容量10
- 若1.5倍容量仍不够存放当前数据,直接使用需要的最小容量
更多推荐


所有评论(0)