分析ArrayList的源码可以帮助我们深入理解其内部实现和工作原理。下面是对Java中ArrayList的简要源码分析:
1. ArrayList的基本信息
ArrayList是Java集合框架中的一个类,它实现了List接口,是基于数组实现的动态数组。它允许快速随机访问元素,但在插入和删除元素时,性能可能会受到影响。
2. 主要成员变量
在ArrayList的源码中,有几个主要的成员变量:
private transient Object[] elementData;
private int size;
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
elementData
: 这是一个Object类型的数组,用于存储ArrayList中的元素。size
: 这是ArrayList中当前元素的数量。DEFAULT_CAPACITY
: 默认的初始容量,当我们不指定初始容量时,ArrayList会默认使用这个值。EMPTY_ELEMENTDATA
: 空数组的默认值,用于在创建空ArrayList时节省内存。
3. 构造函数
ArrayList有多个构造函数,这里简单介绍一个最常见的构造函数:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
在构造函数中,ArrayList会初始化一个空的数组(elementData
),初始容量为DEFAULT_CAPACITY
(即10)。
4. 添加元素:add方法
ArrayList的add方法用于向列表末尾添加元素,如果需要,会自动扩容。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 确保容量足够
elementData[size++] = e; // 将元素添加到数组末尾
return true;
}
ensureCapacityInternal(int minCapacity)
: 这是一个私有方法,用于确保数组的容量足够以容纳指定的最小元素数。如果当前容量不够,则会进行扩容。elementData[size++] = e;
: 将元素添加到数组末尾,并将size(当前元素数量)递增。
5. 扩容机制:ensureCapacityInternal方法
当添加元素时,如果当前容量不足,就需要扩展数组。以下是ensureCapacityInternal
方法的简化版本:
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++; // 结构修改次数
// 如果需要扩容
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);
}
ensureCapacityInternal
方法会根据需要进行扩容操作,如果当前容量不够,则调用grow
方法进行扩容。grow
方法会创建一个新的更大容量的数组,并将原数组中的元素复制到新数组中。
6. 获取元素:get方法
ArrayList的get方法用于获取指定位置的元素:
public E get(int index) {
rangeCheck(index); // 检查索引是否合法
return elementData(index);
}
rangeCheck(int index)
: 检查索引是否在有效范围内,如果不在范围内会抛出IndexOutOfBoundsException
。elementData(int index)
: 返回指定索引位置的元素。
7. 删除元素:remove方法
ArrayList的remove方法用于删除指定位置的元素:
public E remove(int index) {
rangeCheck(index); // 检查索引是否合法
modCount++;
E oldValue = elementData(index); // 获取要删除的元素
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index, numMoved);
elementData[--size] = null; // help GC
return oldValue;
}
System.arraycopy
: 当删除元素后,将后续元素向前移动以填补空缺。elementData[--size] = null;
: 将末尾的元素置为null,帮助垃圾回收器进行回收。
8. 总结
ArrayList的源码分析帮助我们理解了其内部的工作机制,特别是如何实现动态扩展和元素的增删操作。它的基于数组的实现提供了快速的随机访问能力,但在频繁插入和删除操作时可能会有性能问题。对于更深入的理解和学习,建议查阅Java官方文档以及进一步阅读相关的数据结构和算法书籍。