在Java中,ArrayList
是一种基于数组实现的数据结构,它是 List
接口的一个常用实现。ArrayList
提供了动态数组的功能,可以在运行时动态地调整数组的大小。以下是对 ArrayList
的源码分析和使用示例。
基本数据结构
ArrayList
的内部数据结构基本上是一个数组。在Java的 ArrayList
类中,这个数组是用 Object[]
类型定义的,可以容纳任何类型的对象。
关键属性
ArrayList
主要有如下几个关键属性:
Object[] elementData
:这是存储ArrayList
元素的数组。int size
:表示ArrayList
中实际存储的元素数量。
构造函数
ArrayList
提供几个构造函数,最常用的有:
ArrayList()
:创建一个空列表。ArrayList(int initialCapacity)
:创建一个具有指定初始容量的空列表。ArrayList(Collection<? extends E> c)
:创建一个包含指定集合的元素的列表。
动态扩容
当向 ArrayList
添加元素时,如果内部数组已满,就需要进行扩容。默认情况下,每次扩容会增长50%
的容量。
源码解析(部分)
以下代码是ArrayList
的一部分简化版本,用于展示动态扩容的逻辑:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private static final int DEFAULT_CAPACITY = 10; // 默认的数组大小
private static final Object[] EMPTY_ELEMENTDATA = {};
transient Object[] elementData; // 存储ArrayList元素的数组
private int size; // ArrayList中元素的个数
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
}
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 确保容量
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
if (minCapacity - elementData.length > 0) {
grow(minCapacity);
}
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 增长50%
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
代码演示
以下是如何使用 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");
// 遍历ArrayList
for (String fruit : list) {
System.out.println(fruit);
}
// 获取元素
String item = list.get(1);
System.out.println("The second fruit is: " + item);
// 数组大小
int size = list.size();
System.out.println("The size of the list is: " + size);
// 删除元素
list.remove("Banana");
System.out.println("After removal: " + list);
}
}
细节详尽
一些重要的点需要注意:
-
线程不安全:
ArrayList
不是线程安全的。如果多线程环境中需要使用ArrayList
,则必须通过外部方法来同步访问。 -
快速失败迭代器:
ArrayList
的迭代器是快速失败的,即在迭代过程中如果集合被修改了,则会抛出ConcurrentModificationException
。 -
空间复杂度:
ArrayList
有可能持有比其实际元素数量更多的内存,因为它可能会预留额外的空间以减少扩容操作。
通过这样深入、详尽的解析和代码示例,我们可以全面地理解 ArrayList
的工作原理和使用方式,并在实际编程中根据需要做出合适的选择。