Java 集合源码解析系列:
- 拆行解码 Java 集合源码之总览
- 拆行解码 Java 集合源码之 Collection 的三大体系
- 拆行解码 Java 集合源码之迭代器
- 拆行解码 Java 集合源码之 ArrayList
- 拆行解码 Java 集合源码之 LinkedList
- 拆行解码 Java 集合源码之 HashMap
- 拆行解码 Java 集合源码之 Hashtable
- 拆行解码 Java 集合源码之 LinkedHashMap
- 拆行解码 Java 集合源码之 PriorityQueue
- 拆行解码 Java 集合源码之 ArrayDeque
ArrayList 特性
- 数据结构:Object[],可动态扩容(新建数组的方式)
- 允许元素为 Null。
- 非线程安全。可使用 Collections.synchronizedList 包装为线程安全列表。
- 支持随机访问,通过元素索引:RandomAccess 接口标识(无任何方法,仅做标识)。
- Collections.binarySearch() 对于传入的接口,会判断是否实现了 RandomAccess。
- 插入和删除元素的时间复杂度受元素位置的影响。
源码
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 = {};
/**
* 默认容量的初始空数组(无参构造函数)。相当于是懒加载的标志.
* 注意: 1.7 是饿汉式, 构造时就构建出默认容量的数组
* 下次扩容时,如果数组为该值,则至少扩容为默认容量。详细流程可见扩容
* 注意是至少,如果指定扩容为 5,那还是会扩容为默认容量 10。
* 不指定扩容,则默认 10。
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 存储ArrayList的元素的数组缓冲区。
* ArrayList的容量是此数组缓冲区的长度。
* 添加第一个元素时,任何具有elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList都将扩展为DEFAULT_CAPACITY。
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* 实际添加的元素数量
*/
private int size;
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 ArrayList() {
// 只有添加元素时才会开辟有容量的数组
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// defend against c.toArray (incorrectly) not returning Object[]
// (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
// 如果elementData不是Object类型数据(c.toArray可能返回的不是Object类型的数组所以加上下面的语句用于判断)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
// 根据集合创建时, 如果原集合为空, 则容量为 0
this.elementData = EMPTY_ELEMENTDATA;
}
}
/**
* 将 数组长度 调整为 实际元素的数量
*/
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
/**
* 元素搜索、元素判存、元素索引是依赖于 indexOfRange 和 lastIndexOfRange。
* 前者正向,从前往后;后者逆向,从后往前。
* 判断指定索引范围[start, end]内, 元素的索引位置.
* 全局的话, start = 0, end = size (注意是实际元素长度,不是数组容量)。
*/
int indexOfRange(Object o, int start, int end) {
Object[] es = elementData;
if (o == null) {
for (int i = start; i < end; i++) {
if (es[i] == null) {
return i;
}
}
} else {
for (int i = start; i < end; i++) {
if (o.equals(es[i])) {
return i;
}
}
}
return -1;
}
int lastIndexOfRange(Object o, int start, int end) {
Object[] es = elementData;
if (o == null) {
for (int i = end - 1; i >= start; i--) {
if (es[i] == null) {
return i;
}
}
} else {
for (int i = end - 1; i >= start; i--) {
if (o.equals(es[i])) {
return i;
}
}
}
return -1;
}
public int lastIndexOf(Object o) {
return lastIndexOfRange(o, 0, size);
}
public <T> T[] toArray(T[] a) {
if (a.length < size)
// 数组不够大, 基于类型新建一个足够分配的数组
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
// 如果数组长度过长, 则紧跟着最后一个元素的位置设置为空, 好让调用者判断元素有多少.
a[size] = null;
return a;
} return oldValue;
/**
* 这个方法抽出来是为了 add 的字节码数量足够少, 来确保 C1 编译优化的循环内联
*/
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
// 注意, 没有空余的位置才去扩容
// 说明数组自身不会预留空间。
// ps: 如果批量插入很多元素时, 可以手动扩容, 预留空间:ensureCapacity
elementData = grow();
elementData[s] = e;
size = s + 1;
}
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
public void add(int index, E element) {
rangeCheckForAdd(index);
modCount++;
final int s;
Object[] elementData;
if ((s = size) == (elementData = this.elementData).length)
// 扩容条件同上
elementData = grow();
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
elementData[index] = element;
size = s + 1;
}
public E remove(int index) {
Objects.checkIndex(index, size);
final Object[] es = elementData;
@SuppressWarnings("unchecked") E oldValue = (E) es[index];
// 实际移除动作
fastRemove(es, index);
return oldValue;
}
/**
* 如果集合类型不一致, 利用迭代器
* 比较元素数量是否一致、元素的顺序是否一致、元素之间是否一致
*/
boolean equalsRange(List<?> other, int from, int to) {
final Object[] es = elementData;
if (to > es.length) {
throw new ConcurrentModificationException();
}
var oit = other.iterator();
for (; from < to; from++) {
if (!oit.hasNext() || !Objects.equals(es[from], oit.next())) {
return false;
}
}
return !oit.hasNext();
}
/**
* 类型一致, 可以利用数组快速比较
*/
private boolean equalsArrayList(ArrayList<?> other) {
final int otherModCount = other.modCount;
final int s = size;
boolean equal;
if (equal = (s == other.size)) {
final Object[] otherEs = other.elementData;
final Object[] es = elementData;
if (s > es.length || s > otherEs.length) {
throw new ConcurrentModificationException();
}
for (int i = 0; i < s; i++) {
if (!Objects.equals(es[i], otherEs[i])) {
equal = false;
break;
}
}
}
other.checkForComodification(otherModCount);
return equal;
}
int hashCodeRange(int from, int to) {
final Object[] es = elementData;
if (to > es.length) {
throw new ConcurrentModificationException();
}
int hashCode = 1;
for (int i = from; i < to; i++) {
Object e = es[i];
// 计算所有元素的 hashcode, 减少冲突
hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
}
return hashCode;
}
public boolean remove(Object o) {
final Object[] es = elementData;
final int size = this.size;
int i = 0;
// 从前往后, 删除第一个找到的
found: {
if (o == null) {
for (; i < size; i++)
if (es[i] == null)
break found;
} else {
for (; i < size; i++)
if (o.equals(es[i]))
break found;
}
return false;
}
fastRemove(es, i);
return true;
}
private void fastRemove(Object[] es, int i) {
modCount++;
final int newSize;
if ((newSize = size - 1) > i)
// 把 i+1 ~ size 移到 i ~ size -1
// 将 size 置为 null
System.arraycopy(es, i + 1, es, i, newSize - i);
es[size = newSize] = null;
}
public void clear() {
modCount++;
final Object[] es = elementData;
for (int to = size, i = size = 0; i < to; i++)
es[i] = null;
}
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
modCount++;
int numNew = a.length;
if (numNew == 0)
return false;
Object[] elementData;
final int s;
// c 的长度大于 剩余空间, 则扩容的新容量为两个size 之和
if (numNew > (elementData = this.elementData).length - (s = size))
elementData = grow(s + numNew);
System.arraycopy(a, 0, elementData, s, numNew);
size = s + numNew;
return true;
}
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
modCount++;
int numNew = a.length;
if (numNew == 0)
return false;
Object[] elementData;
final int s;
if (numNew > (elementData = this.elementData).length - (s = size))
elementData = grow(s + numNew);
int numMoved = s - index;
if (numMoved > 0)
System.arraycopy(elementData, index,
elementData, index + numNew,
numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size = s + numNew;
return true;
}
protected void removeRange(int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IndexOutOfBoundsException(
outOfBoundsMsg(fromIndex, toIndex));
}
modCount++;
shiftTailOverGap(elementData, fromIndex, toIndex);
}
/** Erases the gap from lo to hi, by sliding down following elements. */
private void shiftTailOverGap(Object[] es, int lo, int hi) {
// 先将后面的元素往前顺位, 再把后面空余的地方置为 null
System.arraycopy(es, hi, es, lo, size - hi);
for (int to = size, i = (size -= hi - lo); i < to; i++)
es[i] = null;
}
boolean batchRemove(Collection<?> c, boolean complement,
final int from, final int end) {
Objects.requireNonNull(c);
final Object[] es = elementData;
int r;
// Optimize for initial run of survivors
for (r = from;; r++) {
if (r == end)
return false;
// 跳过不合法条件的前缀序列
if (c.contains(es[r]) != complement)
break;
}
int w = r++;
try {
for (Object e; r < end; r++)
if (c.contains(e = es[r]) == complement)
es[w++] = e;
// 数组:............w........r
} catch (Throwable ex) {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
// 异常中断, 剩余未判断(r 之后)的元素不再处理, 顺位到 w 后面.
// 数组:............w........r.....s
System.arraycopy(es, r, es, w, end - r);
// 数组:............r.....s..r.....s
w += end - r;
throw ex;
} finally {
modCount += end - w;
shiftTailOverGap(es, w, end);
// 正常分支:............w
// 异常分支:............r.....s
}
return true;
}
}
扩容
默认容量是10;默认扩容1.5倍
1.8 及以后,默认构造是单例空数组,只有第一次添加时才扩容。相当于是懒汉式加载
注意: 1.7 是饿汉式,
构造时就构建出默认容量的数组。
图中两个数值的比较在代码中其实都是通过减法比较的,避免 Integer 溢出的影响。
/**
* 默认容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 空集合的内部结构,避免重复创建空数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 默认容量的初始空数组(无参构造函数)。相当于是懒加载的标志.
* 注意: 1.7 是饿汉式, 构造时就构建出默认容量的数组
* 下次扩容时,如果数组为该值,则至少扩容为默认容量。详细流程可见扩容
* 注意是至少,如果指定扩容为 5,那还是会扩容为默认容量 10。
* 不指定扩容,则默认 10。
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 实际添加的元素数量
*/
private int size;
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 ArrayList() {
// 只有添加元素时才会开辟有容量的数组
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// defend against c.toArray (incorrectly) not returning Object[]
// (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
// 如果elementData不是Object类型数据(c.toArray可能返回的不是Object类型的数组所以加上下面的语句用于判断)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
// 根据集合创建时, 如果原集合为空, 则容量为 0
this.elementData = EMPTY_ELEMENTDATA;
}
}
/**
* 对外提供的扩容方法.
* 在批量添加已知数量的元素时, 可以通过该方法提前且一次性扩容.
* 避免多次扩容的时间损耗
*/
public void ensureCapacity(int minCapacity) {
// 两种情况, 不需要根据指定容量扩容
// 1. 数组容量已满足
// 2. 处于懒汉加载且指定容量小于默认容量. 因为懒加载的默认容量, 可以把它看做'已经开辟了默认容量的数组'.
if (minCapacity > elementData.length
&& !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
&& minCapacity <= DEFAULT_CAPACITY)) {
modCount++;
grow(minCapacity);
}
}
/**
* 同 AbstractCollection
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 至少满足 minCapacity 的扩容,适合批量添加
* 不过依旧受到默认规则的限制.比如 1.5 倍扩容, 默认容量, 最大容量等
*/
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
/**
* 适用于add, 至少满足容量 + 1.
*/
private Object[] grow() {
return grow(size + 1);
}
/**
* 返回至少等于给定最小容量的容量。 如果足够,则返回增加50%的当前容量。
* 除非给定的最小容量大于MAX_ARRAY_SIZE,否则不会返回大于MAX_ARRAY_SIZE的容量
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 新容量默认为原来的 1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {
// 因为是懒加载, 需要判断初始情况
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// 懒加载下, 容量必定大于等于默认容量
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
//默认新容量不满足指定容量, 则按照指定容量
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
// 1.5 扩容可能溢出了,重新根据 minCapacity 判断
: hugeCapacity(minCapacity);
}
/**
* 除非给定的最小容量大于MAX_ARRAY_SIZE,否则不会返回大于MAX_ARRAY_SIZE的容量
*/
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}