ArrayList
ArrayList 能解决什么问题?什么时候使用 ArrayList?
1)ArrayList 底层存储结构是一个对象数组,因此只能存储 Java 对象和 null 值。
2)每个 ArrayList 都有一个容量,容量表示该 ArrayList 当前能容纳的元素个数,
随着元素的增加,ArrayList 会自动扩容,扩容操作通过 System.arraycopy 完成旧元素的拷贝,
因此 ArrayList 适用于元素个数不确定的对象集合。
3)ArrayList 不是线程安全的,多线程并发读写 ArrayList 并且至少有一个线程修改了它的结构【增加、删除元素、扩容等】,
则 ArrayList 将抛出 ConcurrentModificationException 异常。
4)ArrayList 的 size、isEmpty、get、set、iterator 和 listIterator 方法以常量时间运行,其他的操作基本以线性时间运行。
5)ArrayList 实现了 RandomAccess 接口,随机读写以常量时间运行,效率高。
6)ArrayList 的快速失败机制【fast-fail】:iterator 和 listIterator 返回的迭代器是快速失败的,
如果不是通过 ListIterator#remove() 或 ListIterator#add(Object) 方法修改其结构,
则 ArrayList 将尽最大努力抛出 ConcurrentModificationException 异常。
7)ArrayList 的缩容机制:通过 trimToSize 方法将 ArrayList 的容量缩小为当前元素的个数,以减少 ArrayList 的内存占用。
8)ArrayList 的扩容机制:默认为 1.5 倍向下取整扩容,如果批量添加元素,则以 size+newNum 进行扩容。
如何使用 ArrayList?
1)在创建 ArrayList 时可以指定一个合适的初始化容量,以减少频繁扩容带来的性能损耗,使用默认容量值 10 或指定容量值。
2)对于 ArrayList 类型的静态只读属性,通过 trimToSize 方法将 ArrayList 的容量缩小为当前元素的个数,以减少 ArrayList 的内存占用。
3)ArrayList 的随机删除操作会导致部分元素往左 shift,随机删除操作越多,内存拷贝越频繁,性能越差。
使用 ArrayList 有什么风险?
1)ArrayList 的最大容量为 Integer.MAX_VALUE,使用不当可能会导致内存溢出。
2)ArrayList 不是线程安全的,ArrayList 作为共享资源在多线程下执行写操作时,会出现元素丢失的问题。
ArrayList 核心操作的实现原理?
/**
* 通过无参构造函数创建 ArrayList 实例时,第一次扩容的默认容量值。
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 通过带容量构造函数创建 ArrayList 实例时,用于共享的空数组对象
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 通过无参构造函数创建 ArrayList 实例时,用于共享的空数组对象
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* ArrayList 底层存储元素的对象数组,数组的长度就是 ArrayList 的容量
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* ArrayList 包含元素的个数
*/
private int size;
/**
* 创建一个初始化容量为 10 的空 ArrayList 实例
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 创建一个指定初始容量的空 ArrayList 实例
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
// 指定容量为负数时抛出 IllegalArgumentException 异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* 创建一个包含指定集合中所有元素的 ArrayList 实例,集合中的元素按照迭代器顺序返回。
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
// 形参集合非空
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class) {
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
/**
* 将指定的元素添加到列表的尾部
*/
@Override
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
/**
* This helper method split out from add(E) to keep method
* bytecode size under 35 (the -XX:MaxInlineSize default value),
* which helps when add(E) is called in a C1-compiled loop.
*/
private void add(E e, Object[] elementData, int s) {
// 当前元素的个数已经达到底层数组的最大容量,需要进行扩容
if (s == elementData.length) {
elementData = grow();
}
// 存储元素
elementData[s] = e;
// 递增元素个数
size = s + 1;
}
private Object[] grow() {
return grow(size + 1);
}
/**
* 增加 ArrayList 的容量,以保证其至少能够容纳 minCapacity 个元素
*/
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
private int newCapacity(int minCapacity) {
// 获取旧容量
final int oldCapacity = elementData.length;
// 计算新容量(1.5 倍向下取整)
final int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {
// 如果是通过无参构造函数创建的实例,且是第一次添加元素
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 单个添加则返回默认初始容量 10,批量添加并且元素个数大于 10,则返回目标元素个数 minCapacity
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
if (minCapacity < 0) {
throw new OutOfMemoryError();
}
// 通过 addAll 批量添加元素,并且个数超出(剩余容量+原始容量*0.5),则返回目标容量
return minCapacity;
}
// 新容量小于 Integer.MAX_VALUE - 8,则返回 1.5 倍向下取整的值
return newCapacity - MAX_ARRAY_SIZE <= 0
? newCapacity
: ArrayList.hugeCapacity(minCapacity);
}
private static int hugeCapacity(int minCapacity) {
// 目标容量溢出
if (minCapacity < 0) {
throw new OutOfMemoryError();
}
// 新容量等于 Integer.MAX_VALUE - 8,则返回该值,否则返回 Integer.MAX_VALUE
return minCapacity > MAX_ARRAY_SIZE
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
/**
* 将形参集合中的所有元素顺序添加到 ArrayList 的尾部
*/
@Override
public boolean addAll(Collection<? extends E> c) {
final Object[] a = c.toArray();
// 增加结构化修改计数值,在并发修改时可抛出 CME
modCount++;
// 形参集合为空时直接返回
final int numNew = a.length;
if (numNew == 0) {
return false;
}
Object[] elementData;
final int s;
// 新增元素个数大于 ArrayList 剩余可用容量时执行扩容操作
if (numNew > (elementData = this.elementData).length - (s = size)) {
elementData = grow(s + numNew);
}
// 拷贝目标元素到底层数组中
System.arraycopy(a, 0, elementData, s, numNew);
// 增加元素个数
size = s + numNew;
return true;
}
/**
* 获取 ArrayList 指定索引处的元素
*/
@Override
public E get(int index) {
// 索引合法性校验
Objects.checkIndex(index, size);
return elementData(index);
}
@SuppressWarnings("unchecked")
E elementData(int index) {
// 获取底层数组指定索引的元素
return (E) elementData[index];
}
/**
* 替换指定索引处的元素,并返回旧值
*/
@Override
public E set(int index, E element) {
Objects.checkIndex(index, size);
// 读取旧值
final E oldValue = elementData(index);
// 设置新值
elementData[index] = element;
// 返回旧值
return oldValue;
}
/**
* 移除指定索引处的元素
*/
@Override
public E remove(int index) {
Objects.checkIndex(index, size);
final Object[] es = elementData;
@SuppressWarnings("unchecked")
final E oldValue = (E) es[index];
fastRemove(es, index);
return oldValue;
}
/**
* 忽略下标校验,并且无返回值的快速元素移除
*/
private void fastRemove(Object[] es, int i) {
modCount++;
final int newSize;
// 被移除元素不是最后一个元素
if ((newSize = size - 1) > i) {
// 目标索引之后的元素集体左移
System.arraycopy(es, i + 1, es, i, newSize - i);
}
// 将最后一个元素置为 null,并修改总元素个数
es[size = newSize] = null;
}
/**
* 从 ArrayList 中移除第一个匹配形参的元素,通过 Objects.equals(o, get(i)) 进行相等性比较
*/
@Override
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;
}
/**
* 从 ArrayList 中移除包含在形参集合中的所有元素
*/
@Override
public boolean removeAll(Collection<?> c) {
return batchRemove(c, false, 0, size);
}
/**
* created by ZXD at 19 Nov 2018 T 21:24:42
* @param c 目标集合
* @param complement 是否取补集
* @param from 起始索引,包含
* @param end 结束索引,不包含
* @return
*/
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++) {
// 如果未找到则直接返回 false
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;
}
}
} catch (final Throwable ex) {
// 将结束索引后的元素集体左移进行填充
System.arraycopy(es, r, es, w, end - r);
w += end - r;
throw ex;
} finally {
modCount += end - w;
// 整体移动元素填充空隙,并将索引为 size-1 之后的元素置为 null
shiftTailOverGap(es, w, end);
}
return true;
}
/**
* 从 ArrayList 中移除满足函数式断言的所有元素
*/
@Override
public boolean removeIf(Predicate<? super E> filter) {
return removeIf(filter, 0, size);
}
/**
* Removes all elements satisfying the given predicate, from index
* i (inclusive) to index end (exclusive).
*/
boolean removeIf(Predicate<? super E> filter, int i, final int end) {
Objects.requireNonNull(filter);
int expectedModCount = modCount;
final Object[] es = elementData;
// Optimize for initial run of survivors
for (; i < end && !filter.test(ArrayList.elementAt(es, i)); i++) {
;
}
// 首先查找所有需要移除的元素索引,之后进行物理删除
if (i < end) {
final int beg = i;
final long[] deathRow = ArrayList.nBits(end - beg);
deathRow[0] = 1L; // set bit 0
for (i = beg + 1; i < end; i++) {
// 如果满足函数式断言
if (filter.test(ArrayList.elementAt(es, i))) {
// 记录需要删除元素的下标
ArrayList.setBit(deathRow, i - beg);
}
}
// 标记过程中出现多线程并发修改,则抛出 ConcurrentModificationException
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
expectedModCount++;
modCount++;
int w = beg;
for (i = beg; i < end; i++) {
// 从第一个被删除的位置开始,将需要保留的元素顺序进行填充
if (ArrayList.isClear(deathRow, i - beg)) {
es[w++] = es[i];
}
}
shiftTailOverGap(es, w, end);
return true;
} else {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
return false;
}
}
/**
* 形参对象在 ArrayList 中第一次出现的索引,如果不存在相等的元素,则返回 -1
*/
@Override
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;
}
}
}
return -1;
}
/**
* 形参对象在 ArrayList 中最后一次出现的索引,如果不存在相等的元素,则返回 -1
*/
@Override
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;
}
@Override
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/**
* 移除 ArrayList 中不包含在形参集合中的所有元素
*/
@Override
public boolean retainAll(Collection<?> c) {
return batchRemove(c, true, 0, size);
}
/**
* 通过函数式接口将 ArrayList 中的元素进行逐个替换
* created by ZXD at 19 Nov 2018 T 21:51:23
* @param operator
*/
@Override
public void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final int expectedModCount = modCount;
final Object[] es = elementData;
final int size = this.size;
for (int i = 0; modCount == expectedModCount && i < size; i++) {
// 将当前元素进行替换
es[i] = operator.apply(ArrayList.elementAt(es, i));
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
- 通过指定的比较器对 ArrayList 中的元素进行排序
@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 中所有元素的简单迭代器
*/
@Override
public Iterator<E> iterator() {
return new Itr();
}
/**
* 顺序迭代 ArrayList 中所有元素的列表迭代器,支持的操作更丰富
*/
@Override
public ListIterator<E> listIterator() {
return new ListItr(0);
}
/**
* 通过函数式接口顺序消费 ArrayList 中的每个元素
*/
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
final Object[] es = elementData;
final int size = this.size;
for (int i = 0; modCount == expectedModCount && i < size; i++) {
action.accept(ArrayList.elementAt(es, i));
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
/**
* 返回包含 ArrayList 所有元素的对象数组
*/
@Override
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
/**
* 返回包含 ArrayList 所有元素的对象数组,可指定返回类型
*/
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
// 形参数组的长度小于元素个数
if (a.length < size) {
// 拷贝 ArrayList 中的所有元素
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
}
// 拷贝 ArrayList 中的所有元素
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size) {
a[size] = null;
}
return a;
}
/**
* 返回 ArrayList 中的元素个数
*/
@Override
public int size() {
return size;
}
/**
* ArrayList为空时返回true
*/
@Override
public boolean isEmpty() {
return size == 0;
}
/**
* 增加 ArrayList 的容量以至少能够容纳 minCapacity 个元素
*/
public void ensureCapacity(int minCapacity) {
// 通过无参构造函数创建,并且 minCapacity<=10 时不会执行扩容操作
if (minCapacity > elementData.length
&& !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
&& minCapacity <= DEFAULT_CAPACITY)) {
modCount++;
grow(minCapacity);
}
}
/**
* 将容量缩小为 ArrayList 中元素的个数,以节约内存使用
*/
public void trimToSize() {
modCount++;
if (size < elementData.length) {
/**
* ArrayList 为空时,底层数组修改为 EMPTY_ELEMENTDATA
* ArrayList 非空时,通过数组拷贝完成
*/
elementData = size == 0
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
/**
* 移除 ArrayList 中的所有元素,个数置为0,容量保持不变
*/
@Override
public void clear() {
modCount++;
final Object[] es = elementData;
for (int to = size, i = size = 0; i < to; i++) {
es[i] = null;
}
}