Java集合框架之ArrayList
- 前言
- ArrayList源码剖析
- 类图
- 成员变量
- 构造器
- 成员方法
- trimtoSize()
- ensureCapacity(int minCapacity)
- ensureCapacityInternal(int minCapacity)
- ensureExplicitCapacity(int minCapacity)
- get(int index)
- set(int index, E element)
- add(E e)
- add(int index, E element)
- remove(int index)
- remove(Object e)
- fastRemove(int index)
- clear()
- addAll(Collections<? extends E> c)
- removeRange(int fromIndex, int toIndex)
- rangeCheck(int index)
- rangeCheckForAdd(int index)
- outOfBoundsMsg(int index)
- removeAll(Collection<?> c)
- retainAll(Collection<?> c)
- batchRemove(Collection<?> c, boolean complement)
- writeObject(java.io.ObjectOutputStream s)
- readObject(java.io.ObjectInputStream s)
- listIterator(int index)
- listIterator()
- subList(int fromIndex, int toIndex)
- subListRangeCheck(int fromIndex, int toIndex, int size)
- JDK8方法(暂不做说明)
- ArrayList的初始化容量及扩容机制
前言
本着学透的心态,第一次把学习过程写成文章,如有错误请多多包涵!万丈高楼平地起,希望可以一直努力!
ArrayList源码剖析
类图
RandomAccess接口
用于标记支持随机访问
实现了这个接口,用下标访问;
没有实现,用迭代器访问;
(增强for循环)
RandomAccess 作用.
RandomAccess-JDK说明
成员变量
/**
* 默认容量为10
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 用于空实例的共享空数组实例
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 用于默认大小的空实例的共享空数组实例。
* 我们将其与空元素数据区分开来,以了解添加第一个元素时要膨胀多少。
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 真正存放元素的底层数组
* 存储ArrayList元素的数组缓冲区。
* ArrayList的容量是该数组缓冲区的长度。
* 添加第一个元素elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA的任何空ArrayList都将扩展为默认容量
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* ArrayList存放的元素的个数
*
* @serial
*/
private int size;
/**
* 此列表在结构上被修改的次数。结构修改是指那些改变列表大小的修改,或者以某种方式扰乱列表,使得正在进行的迭代可能产生错误的结果。
*
<p>该字段由{@code iterator}和{@code listediterator}方法返回的迭代器和列表迭代器实现使用。
* 如果此字段的值意外更改,迭代器(或列表迭代器)将抛出{@code ConcurrentModificationException},以响应{@code next}、{@code remove}、{@code previous}、{@code set}或{@code add}操作。这提供了<i>快速失效</i>行为,而不是在迭代过程中面对并发修改时的非确定性行为<p> <b>子类使用此字段是可选的</b> 如果子类希望提供fail-fast迭代器(和列表迭代器),那么它只需在其{@code add(int,E)}和{@code remove(int)}方法(以及它重写的任何其他方法,这些方法会导致列表的结构修改)中增加这个字段。对{@code add(int,E)}或{@code remove(int)}的单个调用只能向该字段添加一个,否则迭代器(和列表迭代器)将抛出伪{@code ConcurrentModificationExceptions}。如果实现不希望提供fail-fast迭代器,则可能忽略此字段。
*/
protected transient int modCount = 0;
/**
* The maximum size of array to allocate.可分配的最大的数组大小
* Some VMs reserve some header words in an array.有一些虚拟机会在数组中保留一些头字
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
* 尝试分配更大的数组可能会导致OutOfMemoryError:请求的数组大小超过VM限制
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
为什么elementData是用transient修饰的?
modCount参考
为什么数组最大容量不是Integer.MAX_VALUE
构造器
ArrayList提供了三个构造器
无参构造器
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
而未传入初始大小的情况下,老版本中调用this(10)的方式创建初始大小为10的Object数组。Chuck的jdk 1.8中将elementData赋值为DEFAULTCAPACITY_EMPTY_ELEMENTDATA。
这里需要注意,翻译Constructs an empty list with an initial capacity of ten.可以得知,无参的构造器构建了一个容量为10的空列表,但是结果真的是这样吗?
我们只需要了解DEFAULTCAPACITY_EMPTY_ELEMENTDATA这个变量的真正含义即可,上源码:
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
很明显,DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个空数组,说明并没有初始化一个大小为10的数组,那么什么时候会初始化为10呢?后面的add方法会说明一切。
参数类型为int的构造器
/**
* 初始化一个特定大小的空List
*
* @param initialCapacity list的初始化参数
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayList(int initialCapacity) {
// 如果传入的值大于0,创建一个大小为initialCapacity的Object数组
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 如果传入的值为0,将EMPTY_ELEMENTDATA赋给elementData
this.elementData = EMPTY_ELEMENTDATA;
} else {
// 如果小于0抛出非法参数异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
参数为Collection<? extends E> c的构造器
/**
* 按照集合迭代器返回的顺序,构造一个包含指定集合元素的列表。
*
* @param c 一个元素将被放入list的一个集合
* @throws NullPointerException 如果指定的集合为null则会抛出空指针
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
// https://blog.csdn.net/qq_37186947/article/details/103323985
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 大小为0,elementData=EMPTY_ELEMENTDATA
this.elementData = EMPTY_ELEMENTDATA;
}
}
这里注意: c.toArray might (incorrectly) not return Object[] (see 6260652)
这里是jdk的一个bug,主要问题为c.toArray()返回的不一定是一个Object数组,但是ArrayList的elementData必须为一个Object数组
@Test
public static void main(String[] args){
Parent[] parent = new Child[3]; // 声明数组类型为Parent
System.out.println(parent.getClass()); // 实际类型却是child
parent[0] = new Parent(); // 放入parent对象时会报错ArrayStoreException
}
因此需要判断当前数组类型,如果不是Object类型需要拷贝一个新的Object类型的数组;
成员方法
trimtoSize()
/**
* 将此ArrayList实例的容量修剪为列表当前的大小
* 应用程序可以使用此方法最小化ArrayList实例的大小
*/
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
ensureCapacity(int minCapacity)
/**
* 如果有必要的话增加此arrayList的容量,
* 以确保他至少可以容纳最小容量参数指定的元素数
* @param minCapacity 所需的最小容量
*/
public void ensureCapacity(int minCapacity) {
/*
如果底层数组是是默认构造器构造的DEFAULTCAPACITY_EMPTY_ELEMENTDATA
返回DEFAULT_CAPACITY=10,如果不是返回0
*/
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// 任何大小(如果不是默认元素表)
? 0
// 默认表就是默认大小了
: DEFAULT_CAPACITY;
// 如果最小容量大于当前已有的容量
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
ensureCapacityInternal(int minCapacity)
/**
* 得到最小扩容量
*/
private void ensureCapacityInternal(int minCapacity) {
// 如果底层数组等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA(默认构造器构造的数组)
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 取最小容量和默认容量10最大的那个
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
// 判断是否需要扩容
ensureExplicitCapacity(minCapacity);
}
ensureExplicitCapacity(int minCapacity)
/**
* 判断是否需要扩容
*/
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
get(int index)
/**
* 获取指定下标的元素
*/
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
set(int index, E element)
/**
* (替换)设置指定下标为元素element
*/
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
add(E e)
/**
* 将指定的元素追加到此列表的末尾
*
* @param e 可以被追加到列表的元素
* @return 按照集合的规定添加返回true
*/
public boolean add(E e) {
// 确保当前容器可以容纳当前存储个数+1个元素
ensureCapacityInternal(size + 1); // Increments modCount!!
// 添加元素
elementData[size++] = e;
return true;
}
add(int index, E element)
/**
*在此列表中的指定位置插入指定元素。将当前位于该位置的元素(如果有)和任何后续元素向右移动(将一个元素添加到其索引中)。
*@param index将插入指定元素的索引
*@param-element要插入的元素
*@throws IndexOutOfBoundsException{@inheritDoc}
*/
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
// 将index位置起(包含index)的元素后移一位
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
// 将元素插入到index位置上
elementData[index] = element;
size++;
}
remove(int index)
/**
*删除此列表中指定位置的元素。将任何后续元素向左移动(从其索引中减去一个)。
*
*@param index要删除的元素的索引
*@return从列表中删除的元素
*@throws IndexOutOfBoundsException{@inheritDoc}
*/
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
// size-(index + 1) 判断当前移除的元素是不是最后一个
int numMoved = size - index - 1;
if (numMoved > 0)
// 如果移除的不是最后一个元素,将指定位置以后的元素左移
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 最后一个元素设置为null同时将size - 1
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
remove(Object e)
public boolean remove(Object o) {
// 如果要移除的元素是空的,找到第一次空元素出现的位置并移除
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;
}
fastRemove(int index)
/*
* Private remove方法,该方法跳过边界检查,不返回移除的值。
*/
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
clear()
/**
* 从该列表中删除所有元素。此调用返回后,列表将为空。
*/
public void clear() {
modCount++;
// clear to let GC do its work
// elementData数组所有元素置为null,这样就会被gc回收?
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
addAll(Collections<? extends E> c)
/**
* Appends all of the elements in the specified collection to the end of
* this list, in the order that they are returned by the
* specified collection's Iterator. The behavior of this operation is
* undefined if the specified collection is modified while the operation
* is in progress. (This implies that the behavior of this call is
* undefined if the specified collection is this list, and this
* list is nonempty.)
*
* @param c collection containing elements to be added to this list
* @return <tt>true</tt> if this list changed as a result of the call
* @throws NullPointerException if the specified collection is null
*/
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 += numNew;
return numNew != 0;
}
removeRange(int fromIndex, int toIndex)
/**
* 从列表中移除[fromIndex,toIndex)的元素
* 将任何后续元素向左移动(减少其索引)
* 这个操作将会使列表减少fromIndex - toIndex个元素
* 如果fromIndex==toIndex这个操作就不会有效果
*
* @throws IndexOutOfBoundsException 下列情况会抛出异常
* if {@code fromIndex} or
* {@code toIndex} is out of range
* ({@code fromIndex < 0 ||
* fromIndex >= size() ||
* toIndex > size() ||
* toIndex < fromIndex})
*/
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;
}
rangeCheck(int index)
/**
* 检查给定索引是否在范围内。如果不是,则抛出相应的运行时异常。此方法*不*检查索引是否为负:它总是在数组访问之前立即使用,如果索引为负,则会引发ArrayIndexOutOfBoundsException。
*/
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
rangeCheckForAdd(int index)
/**
* add和addAll使用的一个rangeCheck的版本
* add即为插入,只能在数组0-size闭区间之间进行插入
*/
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
outOfBoundsMsg(int index)
/**
* 构造IndexOutOfBoundsException详细信息。
* 在错误处理代码的许多可能重构中,这种“大纲”
* 在服务器和客户端虚拟机上都表现得最好。
*/
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
removeAll(Collection<?> c)
/**
* 移除这个列表中c包含的所有元素
*
* @param c 需要从当前列表中移除元素的集合
* @return {@code true} 如果由于这个调用列表发生了改变,返回true
* @throws ClassCastException 如果这个列表的元素类型和c中的元素类型不匹配
* @throws NullPointerException c为null,或者此列表包含null元素且c不允许包含空元素
* @see Collection#contains(Object)
*/
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, false);
}
retainAll(Collection<?> c)
/**
* 保留并集
*
* @param c 包含了要在这个list中保留的元素的集合
* @return {@code true} 由于方法调用list改变了返回true
* @throws ClassCastException 如果这个列表的元素类型和c中的元素类型不匹配
* @throws NullPointerException c为null,或者此列表包含null元素且c不允许包含空元素
* @see Collection#contains(Object)
*/
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
batchRemove(Collection<?> c, boolean complement)
/**
* 批量移除
* @param c 指定集合
* @param complement 保留true/移除false本列表中包含的指定集合中的元素
* @return 如果列表发生了修改,返回true
*/
private boolean batchRemove(Collection<?> c, boolean complement) {
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;
}
writeObject(java.io.ObjectOutputStream s)
/**
* 序列化
*
* @serialData The length of the array backing the <tt>ArrayList</tt>
* instance is emitted (int), followed by all of its elements
* (each an <tt>Object</tt>) in the proper order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
readObject(java.io.ObjectInputStream s)
/**
* 反序列化
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}
listIterator(int index)
/**
* 返回列表中元素的列表迭代器(按正确顺序),
* 从列表中的指定位置开始。
* 指定的索引表示初始调用{@link ListIterator#next}将返回的第一个元素。
* 对{@link ListIterator#previous previous}的初始调用将返回指定索引为负1的元素。
*
* <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
*
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
listIterator()
/**
* 返回此列表中元素的列表迭代器(按正确顺序)。
*
* <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
*
* @see #listIterator(int)
*/
public ListIterator<E> listIterator() {
return new ListItr(0);
}
subList(int fromIndex, int toIndex)
/**
* 返回此列表中指定的fromIndex(包含)和toIndex(独占)之间部分的视图。
* (如果fromIndex和toIndex相等,则返回的列表为空。)返回的列表由该列表支持,因此返回列表中的非结构性更改会反映在该列表中,反之亦然。
* 返回的列表支持所有可选的列表操作。
* 这种方法不需要显式的范围操作(数组中通常存在的那种)。
* 通过传递子列表视图而不是整个列表,任何需要列表的操作都可以用作范围操作。
* 例如,以下习惯用法从列表中删除一系列元素:
* 列表子列表[from,to)。清除();
* indexOf(Object)和lastIndexOf(Object)也可以构造类似的习惯用法,Collections类中的所有算法都可以应用于子列表。
* 如果支持列表(即,此列表)在结构上被修改,而不是通过返回的列表,则此方法返回的列表可能并不正确。(结构修改是指改变列表大小,或以其他方式干扰列表,导致正在进行的迭代可能产生错误结果的修改。)
*
* @throws IndexOutOfBoundsException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
*/
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
subListRangeCheck(int fromIndex, int toIndex, int size)
static void subListRangeCheck(int fromIndex, int toIndex, int size) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > size)
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
}
JDK8方法(暂不做说明)
@Override
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();
}
}
/**
* Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
* and <em>fail-fast</em> {@link Spliterator} over the elements in this
* list.
*
* <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
* {@link Spliterator#SUBSIZED}, and {@link Spliterator#ORDERED}.
* Overriding implementations should document the reporting of additional
* characteristic values.
*
* @return a {@code Spliterator} over the elements in this list
* @since 1.8
*/
@Override
public Spliterator<E> spliterator() {
return new ArrayListSpliterator<>(this, 0, -1, 0);
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
// figure out which elements are to be removed
// any exception thrown from the filter predicate at this stage
// will leave the collection unmodified
int removeCount = 0;
final BitSet removeSet = new BitSet(size);
final int expectedModCount = modCount;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
@SuppressWarnings("unchecked")
final E element = (E) elementData[i];
if (filter.test(element)) {
removeSet.set(i);
removeCount++;
}
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
// shift surviving elements left over the spaces left by removed elements
final boolean anyToRemove = removeCount > 0;
if (anyToRemove) {
final int newSize = size - removeCount;
for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
i = removeSet.nextClearBit(i);
elementData[j] = elementData[i];
}
for (int k=newSize; k < size; k++) {
elementData[k] = null; // Let gc do its work
}
this.size = newSize;
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
return anyToRemove;
}
@Override
@SuppressWarnings("unchecked")
public void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final int expectedModCount = modCount;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
elementData[i] = operator.apply((E) elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
@Override
@SuppressWarnings("unchecked")
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
ArrayList的初始化容量及扩容机制
初始化容量
使用无参构造器
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
根据源码可知,无参构造器将DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值给elementData,因此使用无参构造器初始化的容量为0;
参数为int initialCapacity的构造器
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 初始化一个特定大小的空List
*
* @param initialCapacity list的初始化参数
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayList(int initialCapacity) {
// 如果传入的值大于0,创建一个大小为initialCapacity的Object数组
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 如果传入的值为0,将EMPTY_ELEMENTDATA赋给elementData
this.elementData = EMPTY_ELEMENTDATA;
} else {
// 如果小于0抛出非法参数异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
当使用参数为int的构造器时:
当参数大于0,初始化容量为initialCapacity;
当参数等于0,初始化容量为0;
使用参数为Collection<? extends E> c的构造器
/**
* 按照集合迭代器返回的顺序,构造一个包含指定集合元素的列表。
*
* @param c 一个元素将被放入list的一个集合
* @throws NullPointerException 如果指定的集合为null则会抛出空指针
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
// https://blog.csdn.net/qq_37186947/article/details/103323985
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 大小为0,elementData=EMPTY_ELEMENTDATA
this.elementData = EMPTY_ELEMENTDATA;
}
}
使用参数为Collection<? extends E> c的构造器进行初始化:
如果c存储的元素个数大于0,初始化容量为c存储的元素的个数;
否则初始化容量为0;
扩容机制
涉及到的操作add(E e)、add(int index, E element)、addAll(Collection<? extends E> c)及addAll(int index, Collection<? extends E> c)
这里以add(E e)为例进行说明
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ensureCapacityInternal(size + 1)顾名思义,增加了一个元素集合的大小+1,ensureCapacityInternal就是验证插入新元素是否会超出当前数组大小的限制;DEFAULTCAPACITY_EMPTY_ELEMENTDATA是在使用默认的构造函数时赋值给elementData的;
如果当前elementData默认构造器赋值的,取10或者minCapacity最大的那个值进行下一步操作
private void ensureCapacityInternal(int minCapacity) {
// 如果当前elementData默认构造器赋值的,取10或者minCapacity最大的那个值进行下一步操作
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
ensureExplicitCapacity根据传入的minCapacity判断,如果minCapacity比当前elementData数组的长度大,进行扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
扩容的代码比较简单,1.5倍扩容,扩容后的大小如果还不够,就直接使用minCapacity;
如果扩容后的大小比数组最大容量限制还大,使用hugeCapacity进行扩容;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
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);
}
如果发现minCapacity小于0直接抛异常;
如果minCapacity比MAX_ARRAY_SIZE还大,容量为Integer.MAX_VALUE;
如果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;
}
参考文章
Java集合框架知识点总结
为什么elementData是用transient修饰的?
modCount参考
为什么数组最大容量不是Integer.MAX_VALUE等