ArrayList的底层是一个数组实现,其源码位于java.util.ArrayList。以下是ArrayList的关键源码解析:
1. 定义和初始化:ArrayList使用一个Object类型的数组来存储元素,以及一个size变量来记录当前元素个数。初始容量为10。
private static final int DEFAULT_CAPACITY = 10;
private Object[] elementData;
private int size;
这段代码定义了一些关键的成员变量。
private static final int DEFAULT_CAPACITY = 10;
这是一个私有的静态常量,表示 ArrayList 的默认初始容量。当没有指定初始容量时,ArrayList 会使用这个默认值。private Object[] elementData;
这是一个私有的 Object 类型的数组,用于存储 ArrayList 的元素。ArrayList 的底层数据结构就是这个数组。private int size;
这是一个私有的整型变量,表示 ArrayList 当前包含的元素数量。它记录了实际存储在 elementData 数组中的元素个数。
通过这些成员变量,ArrayList 实现了动态数组的功能。当添加元素时,如果当前元素数量超过了 elementData 数组的长度,ArrayList 就会进行扩容操作,创建一个更大的数组,并将元素从旧数组复制到新数组中。扩容后,elementData 数组的长度会增加。
需要注意的是,elementData 数组的长度可能会大于实际存储的元素数量(size 变量的值)。这是为了避免每次添加或删除元素时都进行数组的调整操作,从而提高性能。
这些成员变量是 ArrayList 实现的重要组成部分,它们在 ArrayList 的各种方法中被使用和更新,以实现元素的添加、删除和查询等功能。
2. 扩容操作:当元素个数超过当前容量时,会触发扩容操作。默认情况下,扩容为当前容量的1.5倍。使用ensureCapacityInternal方法来确保容量足够。
这几段代码是 ArrayList 类中与数组扩容相关的方法。让我逐个解释这些方法的作用。
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
ensureCapacityInternal
方法用于确保 ArrayList 内部的容量足够存储指定的最小容量 minCapacity
。如果 elementData
数组是默认初始容量的空数组(即没有添加过元素),则会将 minCapacity
与默认容量 DEFAULT_CAPACITY
中的较大值进行比较,并将较大值赋给 minCapacity
。然后调用 ensureExplicitCapacity
方法来确保容量足够。
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
ensureExplicitCapacity
方法用于确保 elementData
数组的容量至少能够存储 minCapacity
个元素。首先,modCount++
用于记录 ArrayList 的结构修改次数,以支持迭代器的快速失败机制。然后,通过比较 minCapacity
和 elementData.length
的差值,判断是否需要进行扩容操作。如果差值大于 0,则调用 grow
方法进行扩容。
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
grow
方法用于实际进行数组的扩容操作。首先,获取当前 elementData
数组的长度 oldCapacity
。然后,计算新的容量 newCapacity
,通过将 oldCapacity
右移一位并加上 oldCapacity
来实现扩容。这里使用位运算右移一位相当于将 oldCapacity
除以 2,因为右移一位等价于除以 2 的整数除法。
接下来,判断 newCapacity
是否小于 minCapacity
,如果是,则将 minCapacity
赋给 newCapacity
,以确保扩容后的容量不小于 minCapacity
。
然后,通过比较 newCapacity
和 MAX_ARRAY_SIZE
的差值,判断是否超过了数组的最大容量限制。如果超过了,则调用 hugeCapacity
方法来获取一个合适的最大容量值。
最后,使用 Arrays.copyOf
方法将 elementData
数组复制到一个新的数组中,并将新数组赋给 elementData
,完成扩容操作。
这些方法共同实现了 ArrayList 的动态扩容功能,以确保数组容量能够满足添加元素的需求。
3. 添加元素:使用add方法来添加元素到ArrayList中。先确保容量足够,然后将元素添加到数组末尾,并更新size。
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
这段代码是 ArrayList 类中的 add
方法,用于向 ArrayList 中添加元素。让我逐行解释这段代码的作用。
add
方法的参数是要添加的元素 e
,返回值为布尔类型,表示添加操作是否成功。
首先,调用 ensureCapacityInternal
方法来确保 ArrayList 内部的容量足够存储新元素。size + 1
表示当前元素数量加上要添加的一个元素。ensureCapacityInternal
方法会根据需要进行数组扩容操作,以确保容量足够。
然后,将要添加的元素 e
放入 elementData
数组中的下一个位置,即 elementData[size]
。注意,这里使用了后缀自增运算符 size++
,先将 size
的值赋给 elementData[size]
,然后将 size
的值加 1。
最后,返回 true
,表示添加操作成功。
这段代码实现了向 ArrayList 中添加元素的功能。它首先确保容量足够,然后将元素放入数组中,并更新元素数量。
4. 删除元素:使用remove方法来删除指定位置的元素。通过System.arraycopy方法将删除点之后的元素向前移动,然后更新size。
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; // 清空最后一个位置
return oldValue;
}
这段代码是 ArrayList 类中的 remove
方法,用于移除指定索引位置的元素。让我逐行解释这段代码的作用。
remove
方法的参数是要移除的元素的索引 index
,返回值为被移除的元素。
首先,调用 rangeCheck
方法来检查索引是否越界。如果索引超出了有效范围,会抛出 IndexOutOfBoundsException
异常。
然后,modCount++
用于记录 ArrayList 的结构修改次数,以支持迭代器的快速失败机制。
接下来,通过调用 elementData(index)
方法获取要移除的元素,并将其赋给 oldValue
。
然后,计算需要移动的元素个数 numMoved
。size - index - 1
表示从要移除的索引位置开始,到最后一个元素之间的元素个数。
如果有需要移动的元素(即 numMoved > 0
),则使用 System.arraycopy
方法将后面的元素向前移动,以填补被移除的元素位置。具体来说,将 elementData
数组中从 index+1
开始的 numMoved
个元素复制到 elementData
数组中从 index
开始的位置。
最后,将 elementData
数组的最后一个位置设置为 null
,以清空被移除的元素。
最后,返回被移除的元素 oldValue
。
这段代码实现了从 ArrayList 中移除指定索引位置的元素,并将后续元素向前移动的功能。
5. 获取元素:使用get方法来获取指定位置的元素。直接通过索引访问数组中的元素。
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
这段代码是 ArrayList 类中的 get
方法,用于获取指定索引位置的元素。让我逐行解释这段代码的作用。
get
方法的参数是要获取的元素的索引 index
,返回值为对应索引位置的元素。
首先,调用 rangeCheck
方法来检查索引是否越界。如果索引超出了有效范围,会抛出 IndexOutOfBoundsException
异常。
然后,通过调用 elementData(index)
方法获取指定索引位置的元素,并将其返回。
这段代码实现了从 ArrayList 中获取指定索引位置的元素的功能。它首先检查索引的有效性,然后直接通过索引访问 elementData
数组获取对应位置的元素,并将其返回。
其他方法:ArrayList还提供了一系列其他方法,如set用于替换指定位置的元素,size用于获取元素个数,isEmpty用于判断是否为空,等等。
以上是ArrayList底层实现和源码的简要分析,希望能帮助理解ArrayList的工作原理。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。