ArrayList源码分析,你需要知道的所有知识点!("深入解析ArrayList源码:你需要掌握的核心知识点全览!")
原创
一、ArrayList简介
ArrayList是Java中常用的动态数组实现,它提供了类似于数组的随机访问能力,同时具有动态扩展数组长度的特性。下面我们将深入分析ArrayList的源码,以掌握其核心知识点。
二、ArrayList的核心属性
ArrayList的核心属性核心包括以下几个:
// 默认初始容量
private static final int DEFAULT_CAPACITY = 10;
// 空数组实例
private static final Object[] EMPTY_ELEMENTDATA = {};
// 存储元素的数组
transient Object[] elementData;
// 实际元素数量
private int size;
其中,elementData
是存储元素的数组,是ArrayList的核心。
三、构造函数
ArrayList提供了多种构造函数,以下是几种常见的构造函数实现:
// 默认构造函数
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// 指定初始容量的构造函数
public ArrayList(int initialCapacity) {
if (initialCapacity >= 0) {
this.elementData = new Object[initialCapacity];
} else {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
}
// 从Collection集合中构造ArrayList
public ArrayList(Collection extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[]
// array with >= c.size().emptyCheck uses (size==0) trick to check this
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
四、扩容机制
ArrayList的扩容机制是其核心特性之一。当数组容量不足以容纳更多元素时,ArrayList会自动扩容。以下是扩容方法的核心实现:
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容为原来的1.5倍
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
扩容过程核心包括检查当前数组是否需要扩容,如果需要,则将数组容量扩大为原来的1.5倍。
五、添加元素
ArrayList提供了多种添加元素的方法,以下是添加元素到数组末尾的方法实现:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 确保数组有足够空间
elementData[size++] = e; // 添加元素到数组末尾
return true;
}
在添加元素之前,会先调用ensureCapacityInternal
方法确保数组有足够的空间。
六、随机访问元素
ArrayList赞成随机访问元素,以下是随机访问元素的方法实现:
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMessage(index));
}
随机访问元素的时间错综度为O(1),这是由于ArrayList底层是通过数组实现的。
七、删除元素
ArrayList提供了删除元素的方法,以下是删除指定索引元素的方法实现:
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; // clear to let GC do its work
return oldValue;
}
删除元素后,需要将被删除元素之后的所有元素向前移动一位,以填补空缺。
八、遍历元素
ArrayList赞成多种遍历行为,以下是使用迭代器遍历元素的示例:
public Iterator
iterator() { return new Itr();
}
private class Itr implements Iterator
{ int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
迭代器在遍历过程中,会检查modCount值,以确保在遍历过程中ArrayList没有出现结构性修改。
九、序列化和反序列化
ArrayList实现了Serializable接口,于是赞成序列化和反序列化。以下是序列化方法的核心实现:
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
int expectedModCount = modCount;
s.defaultWriteObject();
s.writeInt(size); // 写入数组实际元素数量
for (int i=0; i
s.writeObject(elementData[i]); // 写入每个元素
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
反序列化过程则是将序列化的数据恢复为ArrayList实例。
十、总结
ArrayList是Java中常用的动态数组实现,其源码分析涉及构造函数、扩容机制、添加元素、随机访问元素、删除元素、遍历元素、序列化和反序列化等多个方面。掌握这些核心知识点,有助于我们更好地领会和运用ArrayList,尽或许降低损耗程序性能和稳定性。