本JDK源码阅读笔记基于OpenJDK 13 : https://github.com/openjdk/jdk

一些可能表述或理解不当,请见谅

0.前言

之前跟着芋道源码精尽 JDK 源码解析看了一遍,过了一个月后发现不做笔记不复习基本都忘光了,于是萌生了搭建一个博客来记录一下笔记,当是给自己挖一个坑吧。

1.概述

ArrayList 是一个数组队列,相当于动态数组。它由数组实现,随机访问效率高,随机插入、随机删除效率低。

2.类图

ArrayList 实现的接口、继承的抽象类,如下图所示:

ArrayList.jpg

  • java.util.AbstractList 提供了 List 接口的骨架实现,大幅度的减少了实现迭代遍历相关操作的代码。如 #iterator()#indexOf(Object o) 等方法
  • java.util.List 提供数组的添加、删除、修改、迭代遍历等操作
  • java.util.RandomAccess 表示 ArrayList 里的元素可以被高效的随机访问,以下标数字的方式获取元素
  • java.io.Serialiable 表示 ArrayList 支持序列化和反序列化操作,具有固定的 serialVersionUID 属性值
  • java.lang.Cloneable 表示 ArrayList 支持调用 Object 的 #clone() 方法实现拷贝

3.属性

ArrayList 的属性只有两个:

02.png

  • elementData 元素数组

  • size 数组大小。 size 代表 ArrayList 已经使用 elementData 的元素的数量,调用 #size() 方法也是返回该属性大小。并且,当添加新的元素时,恰好其就是元素添加到数组的下标。然而, ArrayList 真正的大小是 elementData 的大小。

源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
*
* 元素数组
*
* 当添加新的元素时,如果该数组容量不足,会创建新数组,并将原数组的元素拷贝到新数组。
* 之后,将该变量的内存地址指向该新数组。
*
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData ``` DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access

/**
*
* 已使用的数组的大小
*
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;

4.构造方法

ArrayList一共有3个构造方法

  1. #ArrayList(int initialCapacity)

根据传入的容量来创建数组,合理使用避免扩容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public ArrayList(int initialCapacity) {
// 初始化容量大于0时, 创建Object数组
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
// 初始化容量等于0时, 指向 EMPTY_ELEMENTDATA 对象
// 添加元素时, 会进行扩容创建需要的数组
} else if (initialCapacity ``` 0) {
this.elementData = EMPTY_ELEMENTDATA;
// 初始化容量小于0时, 抛出异常
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
  1. #ArrayList()

无参默认构造函数

1
2
3
4
5
6
7
8
/**
* 无参数构造
*
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
  1. #ArrayList(Collection<? extends E> c)

传入 c 集合,作为 ArrayList 的 elementData 进行初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public ArrayList(Collection<? extends E> c) {
// 将c转换为Object数组
elementData = c.toArray();
// 如果数组长度大于0
if ((size = elementData.length) != 0) {
// defend against c.toArray (incorrectly) not returning Object[]
// (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
// 如果集合元素不是Object[]类型, 则会创建新的Object[], 并将elementData赋值到其中, 最后赋值给elementData
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
// 如果数组长度等于0, 则使用EMPTY_ELEMENTDATA
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
  • 附: ArrayList 的三个常量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 默认初始化容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
*
* 共享的空数组对象
*
* 在{@link #ArrayList(int)} 或 {@link #ArrayList(Collection)} 构造方法中,
* 如果传入的初始化大小或者集合大小为0时,将{@link #elementData}指向它
*/
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
* 共享的空数组对象, 用于{@link #ArrayList()} 构造方法.
*
* 通过使用该静态变量, 和{@link #EMPTY_ELEMENTDATA}在第一次添加元素时区分开来
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
  • 一般认为在初始化不指定容量时,ArrayList的默认大小为 10 。但实际上是初始化为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 这个空数组,原因是考虑到部分场景下, ArrayList 被初始化而实际并未使用。所以,ArrayList初始化时是个空数组,只有添加元素后,才会扩容为容量 10 的数组。

  • DEFAULTCAPACITY_EMPTY_ELEMENTDATA 首次扩容 10 ,而 EMPTY_ELEMENTDATA 按照 1.5 倍扩容

5.添加元素与扩容

5.1.#add(E e)——添加单个元素

顺序添加元素到末尾,若容量不够会先进行扩容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public boolean add(E e) {
// 增加数组修改次数, 父类AbstractList上, 定义了modCount属性, 用于记录数组修改次数
modCount++;
// 添加元素
add(e, elementData, size);
// 返回添加成功
return true;
}

private void add(E e, Object[] elementData, int s) {
// 如果容量不够, 进行扩容
if (s ``` elementData.length)
elementData = grow();
// 在数组末尾添加元素
elementData[s] = e;
// 数量加一
size = s + 1;
}

5.2.#add(int index, E element) ——插入单个元素到指定位置

将 index + 1 位置开始的元素往后挪 1 位,再把元素插入到指定位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public void add(int index, E element) {
// 校验位置是否在数组范围内
rangeCheckForAdd(index);
// 增加数组修改次数
modCount++;
// 如果数组大小不足, 进行扩容
final int s;
Object[] elementData;
if ((s = size) ``` (elementData = this.elementData).length)
elementData = grow();
// 将index+1位置开始的元素往后挪
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
// 设置元素到指定的位置
elementData[index] = element;
// 数组大小加一
size = s + 1;
}

private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

5.3.#grow()——数组扩容

当 elementData 容量不足时,会进行扩容。扩容首先创建一个新的更大的数组,一般是 1.5 倍大小,然后利用 **java.utils.Arrays#copyOf(T[], int)** 拷贝原有的数组到新数组,返回新数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private Object[] grow() {
// 最小需要扩容1
return grow(size + 1);
}

private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
// 如果原容量大于0, 或者数组不是DEFAULTCAPACITY_EMPTY_ELEMENTDATA时, 计算新的数组大小, 并创建扩容
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 计算新的数组大小
// 简单来说是Math.max(minGrowth, prefGrowth) + oldLength
// 一般情况下, 是1.5倍扩容(>> 1 为右移操作,相当于除以 2). 但是存在两个特殊情况:
// 1> 初始化数组要求大小为0时, 此时使用minCapacity传入的1
// 2> 添加多个元素时, 传入的minCapacity不再仅仅加1,
// 而是扩容到elementData恰好可以添加多个元素, 而该数量可能会超过当前size的1.5倍
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
// 如果是DEFAULTCAPACITY_EMPTY_ELEMENTDATA数组, 直接创建新的数组
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}

5.4.#addAll(Collection<? extends E> c)——添加多个元素

在数组末尾批量添加多个元素,可以避免多次扩容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public boolean addAll(Collection<? extends E> c) {
// 转换成a数组
Object[] a = c.toArray();
// 增加修改次数
modCount++;
// 如果a数组大小为0, 返回ArrayList数组无变化
int numNew = a.length;
if (numNew ``` 0)
return false;
// 如果elementData数组剩余容量不足, 则进行扩容, 扩至能容纳a数组
Object[] elementData;
final int s;
if (numNew > (elementData = this.elementData).length - (s = size))
elementData = grow(s + numNew);
// 将a复制到elementData从s开始位置
System.arraycopy(a, 0, elementData, s, numNew);
// 数组大小加numNew
size = s + numNew;
return true;
}

5.5.#addAll(int index, Collection<? extends E> c)——从指定位置插入多个元素

从指定index位置插入多个元素,如果 index 开始的位置已经被占用,则把元素往后挪 c 的长度。 * 号位置是差异点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public boolean addAll(int index, Collection<? extends E> c) {
// 校验范围是否在数组内
rangeCheckForAdd(index);

// 转换成a数组
Object[] a = c.toArray();
// 增加修改次数
modCount++;
// 如果a数组大小为0, 返回ArrayList数组无变化
int numNew = a.length;
if (numNew ``` 0)
return false;
// 如果elementData数组剩余容量不足, 则进行扩容, 扩至能容纳a数组
Object[] elementData;
final int s;
if (numNew > (elementData = this.elementData).length - (s = size))
elementData = grow(s + numNew);

// **如果index开始的位置已经被占用, 将它们后移
int numMoved = s - index;
if (numMoved > 0)
System.arraycopy(elementData, index,
elementData, index + numNew,
numMoved);
// 将a复制到elementData从s开始位置
System.arraycopy(a, 0, elementData, index, numNew);
// 数组大小加numNew
size = s + numNew;
return true;
}

5.6.#ensureCapacity(int minCapacity)——主动扩容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
*
* 保证elementData数组容量至少有minCapacity(主动扩容)
*/
public void ensureCapacity(int minCapacity) {
if (minCapacity > elementData.length // 如果minCapacity大于数组的容量
&& !(elementData ``` DEFAULTCAPACITY_EMPTY_ELEMENTDATA // 如果elementData是DEFAULTCAPACITY_EMPTY_ELEMENTDATA的时候
&& minCapacity <= DEFAULT_CAPACITY)) { // 需要最低容量大于DEFAULT_CAPACITY, 因为实际上容量是DEFAULT_CAPACITY
// 数组修改次数加一
modCount++;
// 扩容
grow(minCapacity);
}
}

6. 移除元素与缩容

6.1.#remove(int index)——移除单个元素

移除指定位置的单个元素,并返回该元素

1
2
3
4
5
6
7
8
9
10
11
12
13
public E remove(int index) {
// 校验index不超过size
Objects.checkIndex(index, size);
final Object[] es = elementData;

// 记录该位置的原值
@SuppressWarnings("unchecked") E oldValue = (E) es[index];
// 快速移除
fastRemove(es, index);

// 返回该位置的原值
return oldValue;
}

6.2.#removeRange(int fromIndex, int toIndex)——移除指定区间元素

移除指定区间内多个元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected void removeRange(int fromIndex, int toIndex) {
// 范围不正确, 抛出异常
if (fromIndex > toIndex) {
throw new IndexOutOfBoundsException(
outOfBoundsMsg(fromIndex, toIndex));
}
// 修改次数加一
modCount++;
// 移除[fromIndex, toIndex)的多个元素
shiftTailOverGap(elementData, fromIndex, toIndex);
}

private void shiftTailOverGap(Object[] es, int lo, int hi) {
// 将es从hi位置开始的元素, 移到lo位置开始
System.arraycopy(es, hi, es, lo, size - hi);
// 将从[size - hi + lo, size)的元素置空, 因为已经被挪到前面了
// i = (size -= hi - lo)更新了size
for (int to = size, i = (size -= hi - lo); i < to; i++)
es[i] = null;
}

6.3.#removeAll(Collection<?> c)——移除指定多个元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/**
* 批量移除多个指定元素
* 通过两个变量w(写入位置)和r(读取位置), 按照r顺序遍历数组elementData
* 如果不存在于指定的多个元素中, 则写入elementData的w位置, 然后w+1, 跳到下一个写入位置
* 通过这样的方式, 实现将不存在elementData覆盖写到w位置
*/
public boolean removeAll(Collection<?> c) {
return batchRemove(c, false, 0, size);
}

/**
* complement 参数,翻译过来是“补足”的意思。怎么理解呢?表示如果 elementData 元素在 c 集合中时,是否保留。
* 如果 complement 为 false 时,表示在集合中,就不保留,这显然符合 #removeAll(Collection<?> c) 方法要移除的意图。
* 如果 complement 为 true 时,表示在集合中,就暴露,这符合我们后面会看到的 #retainAll(Collection<?> c) 方法要求交集的意图。
*/
boolean batchRemove(Collection<?> c, boolean complement,
final int from, final int end) {
// 校验c非null
Objects.requireNonNull(c);
final Object[] es = elementData;
int r;
// Optimize for initial run of survivors
// 优化, 顺序遍历elementData数组, 找到第一个不符合complement, 然后结束遍历
for (r = from;; r++) {
// 遍历到尾, 都没有不符合条件的, 直接返回false
if (r ``` end)
return false;
// 如果包含结果不符合complement时, 结束
if (c.contains(es[r]) != complement)
break;
}
// 设置开始写入w为r, 注意不是r++
// r++后, 用于读取下一个位置的元素. 因为通过上面的优化, 我们已经知道es[r]是不符合条件的
int w = r++;
try {
// 继续遍历elementData数组, 如果符合条件, 则进行移除
for (Object e; r < end; r++)
if (c.contains(e = es[r]) ``` complement) // 判断符合条件
es[w++] = e; // 移除的方式, 通过将当前值e写入到w位置, 然后w跳到下一个位置
} catch (Throwable ex) {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
// 如果contains方法发生异常, 则将es从r位置的数组写入到es从w开始的位置
System.arraycopy(es, r, es, w, end - r);
w += end - r;
// 抛出异常
throw ex;
} finally {
// 增加数组修改次数
modCount += end - w;
// 将数组[w, end)位置赋值为null
shiftTailOverGap(es, w, end);
}
return true;
}

6.4.retainAll(Collection<?> c)——求elementData与多个元素交集

一样调用 batchRemove ,区别是传入 true ,即移除不在 c 的元素

1
2
3
public boolean retainAll(Collection<?> c) {
return batchRemove(c, true, 0, size);
}

6.5.#trimToSize()——缩容

建立与 elementData 同长度的数组,并进行复制

1
2
3
4
5
6
7
8
9
10
public void trimToSize() {
// 增加修改次数
modCount++;
// 如果有多余的空间, 则进行缩容
if (size < elementData.length) {
elementData = (size ``` 0)
? EMPTY_ELEMENTDATA // 大小为0时, 直接使用EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size); // 大小大于0时, 则创建大小为size的新数组, 将原数组复制到其中
}
}

7.查找、获取与设定元素

7.1.#indexOf(Object o)——查找元素

从头开始遍历寻找目标元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public int indexOf(Object o) {
return indexOfRange(o, 0, size);
}

int indexOfRange(Object o, int start, int end) {
Object[] es = elementData;
// o为null的情况
if (o ``` null) {
for (int i = start; i < end; i++) {
if (es[i] ``` null) {
return i;
}
}
// o非null的情况
} else {
for (int i = start; i < end; i++) {
if (o.equals(es[i])) {
return i;
}
}
}
// 找不到返回-1
return -1;
}

7.2.#contains(Object o)——判断是否包含该元素

用上述的#indexOf(Object o)方法实现

1
2
3
public boolean contains(Object o) {
return indexOf(o) >= 0;
}

7.3.#lastIndexOf(Object o)——查找最后一个指定元素的位置

#indexOf(Object o) 差不多,就是倒序遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public int lastIndexOf(Object o) {
return lastIndexOfRange(o, 0, size);
}

int lastIndexOfRange(Object o, int start, int end) {
Object[] es = elementData;
// o为null的情况
if (o ``` null) {
for (int i = end - 1; i >= start; i--) {
if (es[i] ``` null) {
return i;
}
}
// o非null的情况
} else {
for (int i = end - 1; i >= start; i--) {
if (o.equals(es[i])) {
return i;
}
}
}
// 找不到返回-1
return -1;
}

7.4.#get(int index)——获取指定位置元素

1
2
3
4
5
6
public E get(int index) {
// 校验index不超过size
Objects.checkIndex(index, size);
// 获得index位置的元素--时间复杂度为O(1)
return elementData(index);
}

7.5. #set(int index, E element)——在指定位置设定元素

1
2
3
4
5
6
7
8
9
10
public E set(int index, E element) {
// 校验index不超过size
Objects.checkIndex(index, size);
// 获得index位置原来的值
E oldValue = elementData(index);
// 修改index位置为新值
elementData[index] = element;
// 返回旧值
return oldValue;
}

8.序列化与反序列化

8.1.#writeObject(java.io.ObjectOutputStream s)——序列化

elementData 带有关键字 transient ,通常来说不会被序列化。

ArrayList 的序列化是先写入非静态、非 transient 属性,然后再遍历写入 elementData 数据,节省空间和时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
*
* 实现ArrayList数组的序列化
*
*/
@java.io.Serial
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out element count, and any hidden stuff
// 获得当前数组的修改次数
int expectedModCount = modCount;
// 写入非静态属性, 非transient属性
s.defaultWriteObject();

// Write out size as capacity for behavioral compatibility with clone()
// 写入size, 主要为了与clone方法兼容
s.writeInt(size);

// Write out all elements in the proper order.
// 逐个写入elementData数组的元素
// elementData是transient定义的, 并不一定全满, 容量有一定的预留
// 直接序列化, 会造成空间的浪费, 所以只序列化[0, size)的元素
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}

// 如果数组修改次数发生了变化, 抛出异常
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}

8.2.#readObject(java.io.ObjectInputStream s)——反序列化

反序列化也是一样,先读取非静态、非 transient 属性,然后再逐个读取元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@java.io.Serial
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {

// Read in size, and any hidden stuff
// 读取非静态、非transient属性
s.defaultReadObject();

// Read in capacity
// 读取size, 不过忽略不用
s.readInt(); // ignored

if (size > 0) {
// like clone(), allocate array based upon size not capacity
SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size);
// 创建elements数组
Object[] elements = new Object[size];

// Read in all elements in the proper order.
// 逐个读取
for (int i = 0; i < size; i++) {
elements[i] = s.readObject();
}

// 赋值给elementData
elementData = elements;
} else if (size ``` 0) {
// 如果size是0, 直接使用空数组
elementData = EMPTY_ELEMENTDATA;
} else {
throw new java.io.InvalidObjectException("Invalid size: " + size);
}
}

99.其他常用方法

99.1.#toArray()——转换为数组

ArrayList 提供两个方法用于把 List 转换为数组

  1. 直接返回 Object 数组
1
2
3
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
  1. 转换成指定类型数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
// 如果传入的数组小于size大小, 则直接复制一个新数组返回
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
// 将elementData复制到a中
System.arraycopy(elementData, 0, a, 0, size);
// 如果传入的数组长度大于size, 则将a[size]赋值为null
if (a.length > size)
a[size] = null;
// 返回a
return a;
}

99.2.#hashCode()——求哈希值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public int hashCode() {
// 获取当前数组修改次数
int expectedModCount = modCount;
// 计算哈希值
int hash = hashCodeRange(0, size);
// 如果修改次数发生改变, 则抛出ConcurrentModificationException异常
checkForComodification(expectedModCount);
return hash;
}

int hashCodeRange(int from, int to) {
final Object[] es = elementData;
// 如果to超过大小, 则抛出异常
if (to > es.length) {
throw new ConcurrentModificationException();
}
// 遍历每个元素, *31求哈希值
int hashCode = 1;
for (int i = from; i < to; i++) {
Object e = es[i];
hashCode = 31 * hashCode + (e ``` null ? 0 : e.hashCode());
}
return hashCode;
}

99.3.#equals(Object o)——判断相等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public boolean equals(Object o) {
// 如果是自己, 直接返回true
if (o ``` this) {
return true;
}

// 如果不是List类型, 直接返回false
if (!(o instanceof List)) {
return false;
}

final int expectedModCount = modCount;
// ArrayList can be subclassed and given arbitrary behavior, but we can
// still deal with the common case where o is ArrayList precisely
// 根据不同类型, 调用不同比对的方法.
// 主要考虑ArrayList可以直接使用其elementData属性, 性能更优
boolean equal = (o.getClass() ``` ArrayList.class)
? equalsArrayList((ArrayList<?>) o)
: equalsRange((List<?>) o, 0, size);

// 如果修改次数发生改变, 则抛出ConcurrentModificationException异常
checkForComodification(expectedModCount);
return equal;
}

boolean equalsRange(List<?> other, int from, int to) {
// 如果to大于es的大小, 说明数组发生改变, 抛出异常
final Object[] es = elementData;
if (to > es.length) {
throw new ConcurrentModificationException();
}
// 通过迭代器遍历other, 然后逐个元素对比
var oit = other.iterator();
for (; from < to; from++) {
// 如果oit没有下一个, 或者元素不相等, 返回false不匹配
if (!oit.hasNext() || !Objects.equals(es[from], oit.next())) {
return false;
}
}
// 通过oit是否遍历完, 实现大小是否相等效果
return !oit.hasNext();
}

private boolean equalsArrayList(ArrayList<?> other) {
// 获得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;
// 如果s大于es或者otherEs的长度, 说明发生变化, 抛出异常
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; // 如果不相等, break
}
}
}
// 如果other修改次数发生变化, 则抛出ConcurrentModificationException异常
other.checkForComodification(otherModCount);
return equal;
}

99.4.#clear()——清空数组

1
2
3
4
5
6
7
8
public void clear() {
// 增加数组修改次数
modCount++;
// 遍历数组, 倒序设置为null
final Object[] es = elementData;
for (int to = size, i = size = 0; i < to; i++)
es[i] = null;
}

99.5.#clone()——克隆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Object clone() {
try {
// 调用父类, 进行克隆
ArrayList<?> v = (ArrayList<?>) super.clone();
// 拷贝一个新的数组
v.elementData = Arrays.copyOf(elementData, size);
// 设置新数组修改次数为0
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}

99.6.#subList(int fromIndex, int toIndex)——创建子数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* SubList 不是一个只读数组,而是和根数组 root 共享相同的 elementData 数组,
* 只是说限制了 [fromIndex, toIndex) 的范围
*
*/
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList<>(this, fromIndex, toIndex);
}

private static class SubList<E> extends AbstractList<E> implements RandomAccess {
/**
* 根ArrayList
*/
private final ArrayList<E> root;
/**
* 父SubList
*/
private final SubList<E> parent;
/**
* 起始位置
*/
private final int offset;
/**
* 大小
*/
private int size;

//.......略

本文作者: Kamadev
      本文地址: https://ckamadev.github.io/2020/04/06/JDK源码阅读笔记——集合I数组ArrayList/
      版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!