Java ArrayList的源码分析?
ArrayList
是 Java Collections Framework 中最常用的动态数组实现之一。它提供了可变大小的数组,能够存储对象并支持快速随机访问。下面我们将对 ArrayList
的源码进行详细分析,包括其内部结构、主要方法及其实现原理。
ArrayList
的核心是一个数组,通常称为 elementData
。当我们创建一个 ArrayList
时,它会初始化一个默认大小的数组。以下是 ArrayList
的部分源码:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
private static final int DEFAULT_CAPACITY = 10;
private Object[] elementData; // 存储元素的数组
private int size; // 当前 ArrayList 中的元素数量
public ArrayList() {
this.elementData = new Object[DEFAULT_CAPACITY];
}
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = new Object[0];
} else {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
}
}
ArrayList
提供了 add
方法来添加元素。这个方法会检查当前数组是否已满,如果已满,则会调用 ensureCapacity
方法扩展数组的大小。
public boolean add(E e) {
ensureCapacity(size + 1); // 确保容量
elementData[size++] = e; // 添加元素并更新大小
return true;
}
private void ensureCapacity(int minCapacity) {
if (minCapacity - elementData.length > 0) {
grow(minCapacity);
}
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 增加50%
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity; // 确保新容量足够
}
elementData = Arrays.copyOf(elementData, newCapacity); // 扩展数组
}
获取元素的操作是通过索引直接访问数组实现的,时间复杂度为 O(1)。
public E get(int index) {
if (index >= size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
return (E) elementData[index];
}
删除元素时,ArrayList
会将后续元素向前移动以填补空缺,并更新大小。
public E remove(int index) {
if (index >= size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
E oldValue = (E) elementData[index];
int numMoved = size - index - 1; // 计算需要移动的元素数量
if (numMoved > 0) {
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
}
elementData[--size] = null; // 清除最后一个元素的引用
return oldValue;
}
ArrayList
不是线程安全的。如果多个线程同时访问一个 ArrayList
,并且至少有一个线程修改了列表,则必须在外部进行同步。可以使用 Collections.synchronizedList
方法来获取一个线程安全的列表。
ArrayList
是一个非常灵活且高效的动态数组实现,适合于需要频繁随机访问和添加元素的场景。它的主要优点是:
然而,ArrayList
在删除和插入操作时可能会导致性能下降,因为需要移动元素。对于频繁插入和删除的场景,可以考虑使用 LinkedList
。
以下是一个简单的示例,展示如何使用 ArrayList
:
import java.util.ArrayList;
public class ArrayListExample {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
// 添加元素
list.add("Apple");
list.add("Banana");
list.add("Cherry");
// 获取元素
System.out.println("First element: " + list.get(0)); // 输出: Apple
// 删除元素
list.remove(1); // 删除 Banana
// 遍历元素
for (String fruit : list) {
System.out.println(fruit);
}
}
}
通过以上分析和示例代码,我们可以更好地理解 ArrayList
的实现原理及其使用方式。