ArrayList源码分析记录
小白发帖,可能有错误的地方,欢迎评论区斧正,求轻喷
ArrayList继承了AbstractList,并实现了List接口
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
1、成员变量
a、序列化的成员变量serialVersionUID
private static final long serialVersionUID = 8683452581122892189L;
b、默认容量DEFAULT_CAPACITY, 空的ArrayList在第一次添加元素之后,容量变成默认容量
private static final int DEFAULT_CAPACITY = 10;
ArrayList的默认容量为【10】
c、空对象数组EMPTY_ELEMENTDATA,用于跟非空数组进行比较
private static final Object[] EMPTY_ELEMENTDATA = {};
d、默认的空对象数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA,会在第一次添加元素的时候跟元素数组进行比较,以了解要进行的扩容大小
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
e、真正存储元素的对象数组elementData,添加的元素实际上都会存在这个数组中
transient Object[] elementData;
transient关键字: transient用于修饰不需要序列化的字段,如果一个引用类型被transient修饰,则其反序列化的值为null,如果一个基本类型被transient修饰,则其反序列化的值为0,如果字段的引用类型是不可序列化的类,则也应该使用transient修饰,它在序列化时会被直接跳过, 也就是在流传输时该关键字修饰的变量不会传输过去。
为什么用transient修饰?
ArrayList在序列化的时候会调用自己内部的writeObject方法,直接将size和element写入ObjectOutputStream;反序列化时调用readObject方法,从ObjectInputStream获取size和element,再恢复到elementData。
为什么不直接用elementData来序列化,而采用上述的方式来实现序列化呢?原因在于elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量,那么有些空间可能就没有实际存储元素,采用上诉的方式来实现序列化时,就可以保证只序列化实际存储的那些元素,而不是整个数组,从而节省空间和时间。
f、ArrayList的实际包含的元素数size
private int size;
g、修改因子 modCount = 0;该变量是父类AbstractList定义的,表示已对该列表进行结构修改的次数,实例中的列表每修改一次就进行一次modCount ++(无论是什么样的修改)
protected transient int modCount = 0;
如果此字段的值意外更改,则迭代器(或列表迭代器)将抛出ConcurrentModificationException以响应next , remove , previous , set或add操作。 面对迭代期间的并发修改,这提供了fail-fast行为,而不是不确定的行为。
2、构造方法
a、构造一个初始容量的ArrayList实例public ArrayList(int initialCapacity)
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);
}
}
b、构造一个初始容量为10的实例public ArrayList()
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
c、构造一个包含指定集合的元素的实例public ArrayList(Collection<? extends E> c),其顺序由集合的迭代器返回
public ArrayList(Collection<? extends E> c) {
//先将集合对象转为数组并赋值给elementdata
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
3、成员方法
a、将实例中的多余的容量缩减为和元素数一样,去掉多余容量空间public void trimToSize(),节省空间
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
b、public void ensureCapacity(int minCapacity),在必要时对ArrayList进行扩容,以确保它至少可以容纳最小容量参数指定的元素数
public void ensureCapacity(int minCapacity) {
//先对元素数组进行判断,是否为空数组(即未进行元素添加),不为空,minExpand取0,为空取默认容量10
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
//如果最小容量参数大于minExpand,则调用ensureExplicitCapacity方法进行扩容
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
c、私有方法private static int calculateCapacity(Object[] elementData, int minCapacity),返回传入的参数和默认容量10 之间较大的一个数
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
d、私有方法private void ensureCapacityInternal(int minCapacity),确保是否使用了默认容量
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
e、确定最终的容量private void ensureExplicitCapacity(int minCapacity),真正调用了扩容方法的地方
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//扩容一次,修改因子就会自增1一次
// overflow-conscious code
//如果传入的参数比现有元素数组的length大(如果是第一次添加,添加之前现有数组的length为0),就会进行扩容
if (minCapacity - elementData.length > 0)
//进入扩容方法
grow(minCapacity);
}
f、真正的扩容方法private void grow(int minCapacity),确保数组动态扩容后能容纳元素
private void grow(int minCapacity) {
// overflow-conscious code
//先拿到原始元素对象数组的length
int oldCapacity = elementData.length;
//扩容元素,如果为第一次添加元素,数组中没有元素,则oldCapacity值为0,如果为第11次添加元素,则oldCapacity为10(因为已经添加了10个元素到数组中了),此时扩容为newCapacity =原容量+原容量右移1位,每次扩容都会扩容为原容量+原容量右移1位
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//最大值判断,确保容量小于Integer的最大值
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//将原数组复制为新的容量的数组并赋值给原数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
g、返回当前list实例包含的元素个数public int size()
public int size() {
return size;
}
h、判断当前list是否为空public boolean isEmpty()
public boolean isEmpty() {
return size == 0;
}
i、判断当前list是否包含某对象public boolean contains(Object o)
public boolean contains(Object o) { return indexOf(o) >= 0;}
j、返回指定元素在此列表中首次出现的索引public int indexOf(Object o);如果此列表不包含该元素,则返回-1
public int indexOf(Object o) {
//如果传入的对象为空,则返回对象数组中第一个为空的索引
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
//如果不为空,则返回对象数组中第一个与该对象相等的元素的索引
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
//如果都没有找到,说明该对象在list中不存在,返回-1
return -1;
}
k、返回指定元素在此列表中最后一次出现的索引public int lastIndexOf(Object o) ;如果此列表不包含该元素,则返回-1
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
l、返回此ArrayList实例的浅表副本public Object clone()。 (元素本身不会被复制。)
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
m、以正确的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组public Object[] toArray()
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
返回的数组将是“安全的”,因为此列表不保留对其的引用。 (换句话说,此方法必须分配一个新数组,即重新生成了一个数组对象实例)。 因此,调用者可以自由修改返回的数组。此方法充当基于数组的API和基于集合的API之间的桥梁。
n、返回list中指定位置的元素public E get(int index)
public E get(int index) {
//先对传入的参数进行范围检查是否越界
rangeCheck(index);
return elementData(index);
}
n1、用指定的元素替换此列表中指定位置的元素public E set(int index, E element)
public E set(int index, E element) {
//先对传入的索引值进行越界判断
rangeCheck(index);
//获取要替换的位置的元素
E oldValue = elementData(index);
//将新元素赋值给要替换的元素的索引位置
elementData[index] = element;
//返回被替换的元素
return oldValue;
}
n2、将指定的元素追加到此列表的末尾public boolean add(E e)
public boolean add(E e) {
//先调用ensureCapacityInternal方法对数组容量进行判断,决定是否扩容,此时的size是列表中元素的个数,而非动态数组的容量
ensureCapacityInternal(size + 1); // Increments modCount!!size+1表示元素的个数增加1个,因此在进行判断时使用增加后的元素个数进行判断
//关于容量的方法调用完毕后,将添加的元素追加到列表的末尾
elementData[size++] = e;
return true;
}
//关联方法
//确定容量的内置方法
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//判断当前动态数组的容量与添加1个元素后的size的大小,并返回较大的1个
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//如果是空数组,初始容量为0,返回默认的容量10(第一次添加时动态数组的length为0,即为空数组,只有数组中有元素后length才会有变化)
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//判断是否扩容的方法
private void ensureExplicitCapacity(int minCapacity) {
//每次对list的操作都会进入这个方法,并将修改因子进行自增
modCount++;
// overflow-conscious code
//如果添加1个元素后的size大于动态数组原有的容量,就进入grow方法进行扩容(第一次添加时数组的length为0,在上面判断size+1与默认容量10的大小时会返回默认大小10),并将该minCapacity传入方法(此时minCapacity为10)
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//真正实现扩容的方法
private void grow(int minCapacity) {
// overflow-conscious code
//获取此时动态数组的容量,第一次添加时为0
int oldCapacity = elementData.length;
//扩容,每次扩容都为原容量+原容量右移1位
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//将数组的容量设置为新的容量
elementData = Arrays.copyOf(elementData, newCapacity);
}
n3、将指定的元素插入此列表中的指定位置public void add(int index, E element)。 将当前在该位置的元素(如果有)和任何后续元素右移(将其索引加一)
public void add(int index, E element) {
//索引检查,判断是否越界,是否小于0
rangeCheckForAdd(index);
//判断是否扩容,逻辑与add(E e)一样
ensureCapacityInternal(size + 1); // Increments modCount!!
//判断扩容完成后,对数组进行复制,将当前在index位置的元素以及后面所有元素都往右移动1位(size-index既是要移动的所有元素数)
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//将index处的元素设为添加进来的元素,并将size自增1
elementData[index] = element;
size++;
}
n4、删除此列表中指定位置的元素public E remove(int index)。 将所有后续元素向左移动(从其索引中减去一个)
public E remove(int index) {
//判断索引是否越界
rangeCheck(index);
//自增修改因子
modCount++;
//获取要删除位置的元素
E oldValue = elementData(index);
//拿到删除后要移动的元素个数
int numMoved = size - index - 1;
if (numMoved > 0)
//复制欲删除元素后的所有元素,向左移动1位
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//将size自减并将最后一个元素置空
elementData[--size] = null; // clear to let GC do its work
//返回删除的元素
return oldValue;
}
n5、如果存在指定元素,则从列表中删除第一次出现的该元素public boolean remove(Object o)。 如果列表不包含该元素,则列表不变
public boolean remove(Object o) {
//如果元素为空,则调用fastRemove删除第一个为空的元素
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
//不为空,则判断列表中是否有该元素,有的话删除,没有的话列表不变
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
//快速删除方法
private void fastRemove(int index) {
//删除也是使列表修改的一种方式,因此修改因子也是自增
modCount++;
//传入的index为要删除的元素的索引,下面的计算得到要删除元素的后面的所有元素个数
int numMoved = size - index - 1;
if (numMoved > 0)
//复制动态数组
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//将size自减并将最后一个元素置空
elementData[--size] = null; // clear to let GC do its work
}
注意:remove不能用在遍历中,否则会因为线程安全问题抛出ConCurrentModifyException异常
n6、从此列表中删除所有元素public void clear()
public void clear() {
modCount++;
// clear to let GC do its work
//遍历列表中的元素,并将每个元素都置空,size置为0
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
n7、添加指定集合到list中public boolean addAll(Collection<? extends E> c)
public boolean addAll(Collection<? extends E> c) {
//先将指定集合转换为数组
Object[] a = c.toArray();
int numNew = a.length;
//确定是否扩容
ensureCapacityInternal(size + numNew); // Increments modCount
//将指定数组添加到原数组的末尾
System.arraycopy(a, 0, elementData, size, numNew);
//size增加指定集合的元素数
size += numNew;
return numNew != 0;
}
n8、从指定位置开始,将指定集合中的所有元素插入此列表public boolean addAll(int index, Collection<? extends E> c)
public boolean addAll(int index, Collection<? extends E> c) {
//判断添加的索引是否越界,是否小于0
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
//确定是否扩容,保障动态数组的容量足够添加
ensureCapacityInternal(size + numNew); // Increments modCount
int numMoved = size - index;
if (numMoved > 0)
//将添加的索引位置后面的元素向后移动numMoved个
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
//将元素添加到数组中
System.arraycopy(a, 0, elementData, index, numNew);
//修改size的值
size += numNew;
return numNew != 0;
}
n9、从此列表中删除索引在fromIndex (包括)和toIndex (不包括)之间的所有元素protected void removeRange(int fromIndex, int toIndex)
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// clear to let GC do its work
int newSize = size - (toIndex-fromIndex);
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
size = newSize;
}
o、从此列表中删除指定集合中包含的所有元素public boolean removeAll(Collection<?> c)
public boolean removeAll(Collection<?> c) {
//要求传入的参数必须不为空,否则报空指异常
Objects.requireNonNull(c);
//调用批量删除方法进行删除
return batchRemove(c, false);
}
p、仅保留此列表中指定集合中包含的元素public boolean retainAll(Collection<?> c)。 换句话说,从该列表中删除所有未包含在指定集合中的元素
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
q、批量删除方法private boolean batchRemove(Collection<?> c, boolean complement)
private boolean batchRemove(Collection<?> c, boolean complement) {
//定义不可变对象数组并将list中的对象数组赋值给它
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
//遍历元素,判断传入的集合是否包含定义的数组对象中的某个元素
if (c.contains(elementData[r]) == complement)
//对数组对象进行操作
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
r、从列表中的指定位置开始,以适当的顺序返回此列表中的元素的列表迭代器public ListIterator<E> listIterator(int index)。 指定的索引指示首次调用next将返回的第一个元素。 最初调用previous将返回指定索引减一的元素。
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
//返回的ListItr对象是ArrayList的内部类,继承自ArrayList另一个内部类Itr,实现了ListIterator接口,而Itr实现了Iterator接口
return new ListItr(index);
}
//上面的方法调用此对象的有参构造
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
//该有参构造调用了Itr类的无参构造
super();
//cursor是父类即Itr定义的变量,表示要返回的下一个元素的索引
cursor = index;
}
内部类Itr
private class Itr implements Iterator<E> {}//供元素遍历
Itr中的方法
//判断迭代列表中是否还有下一个元素
public boolean hasNext() {
return cursor != size;
}
//获取迭代列表的下一个元素
public E next() {
//先检查是否发生了不可预知的引起modCount改变的行为,例如多线程访问,会抛出ConcurrentModificationException异常
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
//将当前列表中的数组对象赋值给新的elementData
Object[] elementData = ArrayList.this.elementData;
//如果遍历的索引大于元素的个数,会抛出异常
if (i >= elementData.length)
throw new ConcurrentModificationException();
//索引加1
cursor = i + 1;
//返回遍历的到的元素,并将此元素的索引赋值给lastRetsc
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();
}
}
s、public void forEach(Consumer<? super E> action) forEach遍历
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
t、根据由指定Comparator引起的顺序对该列表进行排序default void sort(Comparator<? super E> c),来自List接口方法
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
//调用Arrays的sort方法对数组元素按传入的Comparator对象规则进行排序
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}