注:本文档基于
JDK-version 1.8.0_102
编写
实现/继承关系
RandomAccess
标记型接口,表明支持快速随机访问。具体内容可查看 Collections
类中的 binarySearch(..)
方法
Serializable
启用序列化支持
Cloneable
标记型接口,表明该对象可以被克隆,使用Object.clone()
方法
成员变量
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private int size;
DEFAULT_CAPACITY
初始默认容量
EMPTY_ELEMENTDATA
共享空数组,无参构造时使用
DEFAULTCAPACITY_EMPTY_ELEMENTDATA
默认大小的共享空数组
elementData
数据存储缓冲区数组,ArrayList
的所有元素都存储在该数组中
MAX_ARRAY_SIZE
可存储元素数量的最大值,尝试保存元素数量超过该值将导致 OutOfMemoryError
- 内存溢出
一般情况下,由于JVM分配的内存较小,实际可用最大容量远远低于这个值
size
实际存储的元素的数量
构造方法
ArrayList()
空参构造方法,集合元素数组 elementData
初始化为空数组
ArrayList(Collection<? extends E> c)
以原集合构造新集合对象,原集合为空,集合元素数组 elementData
初始化为空数组;否则直接将原集合中的元素按原顺序保存到新集合的元素数组 elementData
中
ArrayList(int initialCapacity)
指定初始化容量构造集合的对象
源码
/**
* 空参构造
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; //保存集合元素的数组初始化为空数组
}
/**
* 参数为指定Collection的构造方法
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
//由于 toArray()方法存在可能返回的不是Object[]的bug,需要对非Object[]的elementData做一次类型转换
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
/**
* 指定初始容量的构造方法
*/
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 static void main(String[] args) {
//空参构造
List<String> stringList = new ArrayList<>();
//参数为Collection的构造方法
//Meat extends Food
List<Meat> meatList = new ArrayList<>();
ArrayList<Food> meatFoodList = new ArrayList<>(meatList);
ArrayList<Food> foodList = new ArrayList<>(meatFoodList);
//指定初始化容量的构造方法
List<Meat> meatList = new ArrayList<>(20);
}
普通方法
add
add(E e)
& add(int index, E element)
//源码
/**
* 集合尾部新增一个新元素
*/
public boolean add(E e) {
//对modCount计数器的计数操作
//确定当前容量是否可以支撑新增一个元素的操作,不足以支撑便进行扩容
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
/**
* 在指定位置插入一个新元素
*/
public void add(int index, E element) {
//检查是否索引越界,该方法会抛出 IndexOutOfBoundsException 异常
rangeCheckForAdd(index);
//对modCount计数器的计数操作
//确定当前容量是否可以支撑新增一个元素的操作,不足以支撑便进行扩容
ensureCapacityInternal(size + 1);
//将新元素插入到指定位置(index), 原集合该位置后面的元素后挪
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
addAll
addAll(Collection<? extends E> c)
& addAll(int index, Collection<? extends E> c)
//源码
/**
* 方法调用对象的尾部新增 参数中的集合中的元素
*/
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
//对modCount计数器的计数累加操作
//确定当前容量是否可以支撑吞并集合的操作,不足以支撑便进行扩容
ensureCapacityInternal(size + numNew);
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
/**
* 方法调用对象的指定位置插入 参数中的集合中的元素,原集合指定位置之后的元素后挪
*/
public boolean addAll(int index, Collection<? extends E> c) {
//检查是否索引越界,该方法会抛出 IndexOutOfBoundsException 异常
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
//对modCount计数器的计数累加操作
//确定当前容量是否可以支撑吞并集合的操作,不足以支撑便进行扩容
ensureCapacityInternal(size + numNew);
int numMoved = size - index;
//扩容后,size >= index 恒成立
if (numMoved > 0)
//中间插入操作
System.arraycopy(elementData, index, elementData, index + numNew, numMoved);
//尾部新增操作
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
remove
remove(int index)
& remove(Object o)
//源码
/**
* 删除指定索引位置的元素
*/
public E remove(int index) {
//检查是否索引越界
rangeCheck(index);
modCount++;
//获取指定索引位置的元素值
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
//索引位置后的元素前移
System.arraycopy(elementData, index+1, elementData, index, numMoved);
// clear to let GC do its work
elementData[--size] = null;
return oldValue;
}
/**
* 根据元素匹配删除
* 方法内部调用的 fastRemove(index)方法 与 remove(int index) 相比较,
* 不再检查索引越界, 不需要获取已删除元素, 其他再无区别
*/
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;
}
removeAll
removeAll(Collection<?> c)
性能较差,数据量较大的情况下不建议使用
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, false);
}
clone
该方法的拷贝是浅拷贝,即不会拷贝集合中的元素
/**
* Returns a shallow copy of this <tt>ArrayList</tt> instance.
* 浅拷贝
* 要想实现深拷贝,需要重写 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);
}
}
fastRemove(int index)
与 remove(int index)
相比没有索引越界的检查, 没有已删除元素的获取和返回, 其他再无区别
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
}
batchRemove(Collection<?> c, boolean complement)
该方法共有两处调用: removeAll(..)
retainAll(..)
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
//遍历元素数组 elementData
// w <= r
//结果是,有 w 个符合判断条件的元素,那么元素数组 0 ~ (w-1) 的索引位置放置的便是这些元素
//在removeAll(..)方法中,由于complement 为 false, 故 0 ~ (w-1) 索引位置的便是要删除的元素
//在retainAll(..)方法中,由于complement 为 true, 故 0 ~ (w-1) 索引位置的便是两个集合共有的元素
for (; r < size; r++)
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// 当 c.contains() 抛出异常的时候 r != size
if (r != size) {
//将抛出异常的元素索引位置后面的元素前移到 w 索引位置之后
System.arraycopy(elementData, r, elementData, w, size - r);
w += size - r;
}
//removeAll(..), 当删除的集合与当前集合中没有任何交集时,w == size, modified == false
//retainAll(..), 当查询的集合与当前集合元素一致时,w == size, modified == false
//注: retainAll(..), 当查询的集合与当前集合元素一致时返回的是false, 只有是包含且元素不一致时才会返回true
//这两种情况都不需要再做处理,return true 即可
if (w != size) {
for (int i = w; i < size; i++) {
//将所有不符合条件的元素全部置为null
elementData[i] = null;
}
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
fastRemove(int index)
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
}
ensureCapacityInternal(int minCapacity)
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
ensureExplicitCapacity(int minCapacity)
在该方法中,会进行计数器的累加操作
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //计数器,来自于父类 AbstractList 的成员属性
if (minCapacity - elementData.length > 0)
//现有 elementData 的容量不足,扩容
grow(minCapacity);
}
ensureCapacity(int minCapacity)
public void ensureCapacity(int minCapacity) {
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;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
grow(int minCapacity)
/**
* 扩容方法
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //原容量加上原容量的一半 即扩容1.5倍
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);
}
hugeCapacity(int minCapacity)
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}