ArrayList 源码+扩容机制
目录
- ArrayList 的底层数据结构是数组,它的容量可以动态增加。在添加大量元素前可以通过
ensureCapacity()
来指定增加的容量,可以减少递增式再分配的数量。 - ArrayList 实现的
RandomAccess
接口是一个标志接口,表明这个 List 集合是支持快速随机访问的。比如在Collections.binarySearch()
中,调用的是Collections.indexedBinarySearch()
方法,而不是Collections.iteratorBinarySearch()
方法。 new ArrayList<>(0)
和new ArrayList<>()
返回的是静态变量空数组,但不是同一个。通过默认构造方法得到的 ArrayList 等到执行add()
添加元素时才会初始化容量(默认为 10),而指定初始化容量为 0 的 ArrayList 在ensureCapacity()
。
扩容机制
-
add(int index, E element)
- **rangeCheckForAdd(index);**如果 index 大于 size,或小于 0,抛出异常
IndexOutOfBoundsException
。 - ensureCapacityInternal(size + 1);
- **ensureExplicitCapacity();**判断是否需要扩容(Explicit 明确的)
- **grow(int minCapacity);**扩容的核心方法
- **ensureExplicitCapacity();**判断是否需要扩容(Explicit 明确的)
- System.arraycopy(…);复制到新的更大的数组,native 方法
- **rangeCheckForAdd(index);**如果 index 大于 size,或小于 0,抛出异常
-
addAll(Collection<? extends E> c)
-
ensureCapacityInternal(size + 1);
- *ensureExplicitCapacity();**判断是否需要扩容(Explicit 明确的)
- **grow(int minCapacity);**扩容的核心方法
- *ensureExplicitCapacity();**判断是否需要扩容(Explicit 明确的)
-
System.arraycopy(…);复制到新的更大的数组,native 方法
-
private void grow(int minCapacity)
- 选取新的容量值 newCapacity :minCapacity 和 原数组长度的 1.5 倍 中的较大值。
- 检查 newCapacity 是否超出 MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8):超出则取 Integer.MAX_VALUE。
- 通过 Arrays.copyOf() 得到新的数组。
System.arrayCopy()
public static void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length)
源阵列中位置 [srcPos
, srcPos+length-1
] 的组件分别复制到目标阵列的位置 [destPos
, destPos+length-1
] 。
Arrays.copyOf()
public static T[] copyOf(T[] original, int newLength)
- 申请一个大小为 newLength 的新数组
- 通过 System.arraycopy 将原数组的数据拷贝到新数组
- 返回新数组
暴露的 ensureCapaticy 方法
// @param minCapacity 所需的最小容量
public void ensureCapaticy(int minCapacity) {
// 判断初始化容量是否为 0
...
ensureExlicitCapacity(minCapacity);
}
在 add 大量元素之前,使用该方法指定容量,以减少增量重新分配的次数。
删除元素操作
删除指定位置的元素,将所有后续元素移到左侧。可能会改变数组中其他元素的位置,但不会改变 容量。
- remove()
- fastRemove()
- removeRange()
附源码 (摘抄自 JavaGuide)
https://javaguide.cn/java/collection/arraylist-source-code/
package java.util;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
/**
* 默认初始容量大小
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 空数组(用于空实例)。
*/
private static final Object[] EMPTY_ELEMENTDATA = {
};
//用于默认大小空实例的共享空数组实例。
//我们把它从EMPTY_ELEMENTDATA数组中区分出来,以知道在添加第一个元素时容量需要增加多少。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
};
/**
* 保存ArrayList数据的数组
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* ArrayList 所包含的元素个数
*/
private int size;
/**
* 带初始容量参数的构造函数(用户可以在创建ArrayList对象时自己指定集合的初始大小)
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//如果传入的参数大于0,创建initialCapacity大小的数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//如果传入的参数等于0,创建空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
//其他情况,抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
*默认无参构造函数
*DEFAULTCAPACITY_EMPTY_ELEMENTDATA 为0.初始化为10,也就是说初始其实是空数组 当添加第一个元素的时候数组容量才变成10
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。
*/
public ArrayList(Collection<? extends E> c) {
//将指定集合转换为数组
elementData = c.toArray();
//如果elementData数组的长度不为0
if ((size = elementData.length) != 0) {
// 如果elementData不是Object类型数据(c.toArray可能返回的不是Object类型的数组所以加上下面的语句用于判断)
if (elementData.getClass() != Object[].class)
//将原来不是Object类型的elementData数组的内容,赋值给新的Object类型的elementData数组
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 其他情况,用空数组代替
this.elementData = EMPTY_ELEMENTDATA;