Java ArrayList 底层方法的自我实现
·
下面是对 Java 中 ArrayList 底层核心方法的自我实现,模拟了其动态数组的基本功能,包括添加、删除、查找、扩容等操作:
import java.util.Arrays;
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() {
this.elementData = EMPTY_ELEMENTDATA;
}
// 有参构造器:指定初始容量
public MyArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("初始容量非法: " + initialCapacity);
}
}
// 获取当前元素数量
public int size() {
return size;
}
// 判断是否为空
public boolean isEmpty() {
return size == 0;
}
// 添加元素到末尾
public boolean add(E e) {
// 确保容量足够(不足则扩容)
ensureCapacityInternal(size + 1);
// 赋值并更新元素数量
elementData[size++] = e;
return true;
}
// 指定位置添加元素
public void add(int index, E element) {
// 检查索引合法性
rangeCheckForAdd(index);
// 确保容量足够
ensureCapacityInternal(size + 1);
// 从index开始的元素后移一位(复制数组)
System.arraycopy(elementData, index, elementData, index + 1, size - index);
// 插入新元素
elementData[index] = element;
size++;
}
// 获取指定位置元素
@SuppressWarnings("unchecked")
public E get(int index) {
rangeCheck(index);
return (E) elementData[index];
}
// 修改指定位置元素
public E set(int index, E element) {
rangeCheck(index);
E oldValue = get(index);
elementData[index] = element;
return oldValue;
}
// 删除指定位置元素
public E remove(int index) {
rangeCheck(index);
E oldValue = get(index);
// 计算需要移动的元素数量
int numMoved = size - index - 1;
if (numMoved > 0) {
// 从index+1开始的元素前移一位
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
}
// 释放最后一个元素的引用(帮助GC)
elementData[--size] = null;
return oldValue;
}
// 删除指定元素(只删除第一个匹配项)
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++) {
if (elementData[index] == null) {
fastRemove(index);
return true;
}
}
} else {
for (int index = 0; index < size; index++) {
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
}
return false;
}
// 快速删除(内部使用,不做索引检查)
private void fastRemove(int index) {
int numMoved = size - index - 1;
if (numMoved > 0) {
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
}
elementData[--size] = null;
}
// 清空集合
public void clear() {
// 释放所有元素引用
for (int i = 0; i < size; i++) {
elementData[i] = null;
}
size = 0;
}
// 检查索引是否越界(用于get/set/remove)
private void rangeCheck(int index) {
if (index >= size) {
throw new IndexOutOfBoundsException("索引越界: " + index + ", 大小: " + size);
}
}
// 检查添加时的索引是否越界
private void rangeCheckForAdd(int index) {
if (index > size || index < 0) {
throw new IndexOutOfBoundsException("索引越界: " + index + ", 大小: " + size);
}
}
// 确保内部容量
private void ensureCapacityInternal(int minCapacity) {
// 如果是初始空数组,最小容量取默认容量和所需容量的最大值
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
// 确保显式容量(判断是否需要扩容)
private void ensureExplicitCapacity(int minCapacity) {
// 如果所需容量超过当前数组长度,则扩容
if (minCapacity - elementData.length > 0) {
grow(minCapacity);
}
}
// 扩容核心方法
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// 扩容为原来的1.5倍(位运算效率更高)
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果扩容后的容量仍不足,则直接使用所需容量
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
// 复制原数组元素到新数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
// 重写toString,方便打印
@Override
public String toString() {
if (size == 0) {
return "[]";
}
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < size; i++) {
sb.append(elementData[i]);
if (i != size - 1) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
}
核心实现说明:
-
底层结构:使用
Object[]数组存储元素,支持泛型(通过类型擦除实现)。 -
容量管理:
- 初始容量默认为 10(无参构造器),也可指定初始容量。
- 当元素数量达到当前容量时,触发扩容,扩容后的容量为原容量的 1.5 倍(通过
oldCapacity + (oldCapacity >> 1)计算)。 - 若扩容后的容量仍不足(如初始容量为 0 时添加大量元素),则直接使用所需的最小容量。
-
核心方法:
add(E e):添加元素到末尾,需先检查容量。add(int index, E element):指定位置插入,需移动后续元素。get(int index)/set(int index, E element):获取/修改指定位置元素,需检查索引合法性。remove(int index)/remove(Object o):删除元素,需移动后续元素并释放引用。
-
索引检查:通过
rangeCheck确保操作的索引在有效范围内,避免数组越界。 -
内存优化:删除元素后主动释放引用(置为
null),帮助垃圾回收(GC)。
使用示例:
public class TestMyArrayList {
public static void main(String[] args) {
MyArrayList<String> list = new MyArrayList<>();
list.add("A");
list.add("B");
list.add(1, "C"); // 在索引1插入"C"
System.out.println(list); // 输出: [A, C, B]
list.set(2, "D");
System.out.println(list.get(2)); // 输出: D
list.remove(0);
System.out.println(list); // 输出: [C, D]
list.remove("D");
System.out.println(list.size()); // 输出: 1
}
}
该实现模拟了 JDK 中 ArrayList 的核心逻辑,但简化了部分细节(如序列化支持、迭代器实现等),适合理解动态数组的底层原理。
更多推荐


所有评论(0)