摘要

ArrayList——源码探究-LMLPHP

ArrayList 是Java中常用的一个集合类,其继承自AbstractList并实现了List, RandomAccess, Cloneable, java.io.Serializable四个接口。本文主要来探究一下ArrayList的代码实现。

构造器

ArrayList 提供了三个构造器,分别是

含参构造器-1

// 含参构造器-1
// 参数含义: 初始化线性表容量
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);
}
}

含参构造器-2

// 含参构造器-2
// 参数含义:其他的集合类型转为ArrayList
public ArrayList(Collection<? extends E> c) {
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;
}
}

无参构造器

// 无参构造器
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

成员变量

// 默认的表容量
private static final int DEFAULT_CAPACITY = 10;
// 构造参数为 0 的时候,默认都指向该数组
private static final Object[] EMPTY_ELEMENTDATA = {};
// 无参构造时默认指向该数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 实际存放数据的数组
transient Object[] elementData;
// 表大小
private int size;
// 修改次数 Modify Count (定义在AbstractList中) 【划重点】
protected transient int modCount = 0;

关于这两个空数和构造器,参考如下代码

ArrayList a1 = new ArrayList(0);
ArrayList a2 = new ArrayList();
ArrayList a3 = new ArrayList();
ArrayList a4 = new ArrayList(0);
Field field = ArrayList.class.getDeclaredField("elementData");
field.setAccessible(true);
System.out.println(field.get(a1) == field.get(a2));
System.out.println(field.get(a2) == field.get(a3));
System.out.println(field.get(a1) == field.get(a4));

以上代码将会输出如下结果

false	# a1.elementData ≠ a2.elementData
true # a2.elementData = a3.elementData
true # a1.elementData = a4.elementData

内部类

// 迭代器实现类,实现了Iterator接口,可以使用增强的for循环
private class Itr implements Iterator<E>{}
// 需要注意的是:ListIterator接口继承于Iterator接口
// ListIterator 和 Iterator最大的区别在于:Iterator单向移动,而ListIterator可以双向移动并且可以增加、设置元素
// forEachRemaining 方法都是向后迭代的
private class ListItr extends Itr implements ListIterator<E>{}
// 为sublist()方法准备的内部类
private class SubList extends AbstractList<E> implements RandomAccess]{}
// 为多核应用开发所准备的Spliterator
static final class ArrayListSpliterator<E> implements Spliterator<E>{}

常用方法

扩容机制

ArrayList的扩容由以下几个方法来实现。要明确的是,ArrayList的容量实际上就是其存放数据的elementData数组的长度,每一次自动的扩容都是由当前表的大小和elementData的长度做对比后而决定的。

    // 供使用者调用的容量初始化方法,在大量增加新数据的情况下,预先确定足够的容量可以减少时间开支(因为会因为表不够大而频繁的扩容)
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;
// 最小能保证表容量为DEFAULT_CAPACITY(10)
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
} // 这个方法供内部调用,也就是在add和addAll里使用的。
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 按最大的算,此处也可以看出来,容量最小也是DEFAULT_CAPACITY(10)
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
} private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
// 不够大就扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
} /**
* 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
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
* 实际的扩容方法
* @param minCapacity the desired minimum capacity
*/
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); // 最大也只能能是MAX_ARRAY_SIZE(有可能是Integer.MAX_VALUE)
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
} private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}

add

  • 默认增加到最后一个元素后面
	public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
  • 在指定位置后面插入
    public void add(int index, E element) {
rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}

addAll

  • 默认增加到最后一个元素后面
    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;
}
  • 在指定位置后面插入
    public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index); Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount,同时确认是否扩容 int numMoved = 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

  • 按下标

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);
elementData[--size] = null; // clear to let GC do its work,防止内存泄露 return oldValue;
}
  • 按元素
	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;
} 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,防止内存泄露
}

set

  • 指定位置
	// 插入新值,返回旧值
public E set(int index, E element) {
rangeCheck(index); E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}

get

  • 指定位置
    public E get(int index) {
rangeCheck(index); return elementData(index);
}

clear

    public void clear() {
modCount++;
// 这里不能简单的把size置为0就完事,要确定本表对每一个元素不再有引用关系,避免内存泄漏
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null; size = 0;
}

trimToSize

一般来说,表的大小要小于等于表的容量,而在内存紧张的时候,可能会用到该方法来使表的容量缩小至表的大小一样大

    public void trimToSize() {
modCount++;
// size 只会 ≤ elementData.length,而等于的时候该方法的目的已经达到就不用做任何事了
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}

indexOf

public int indexOf(Object o) {
// 注意这里区分了 o 是否为 null
// 为null的情况很好理解,因为 null 的含义是确认的
// 但是不为空即是一个对象的话,就需要用到equals方法,所以一般的类会重写equals方法
// Object的equals只是简单的对引用做个比较
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;
}

lastIndexOf

这个方法是与indexOf对应的一个方法,indexOf的实现是正序查找,而本方法是逆序查找

    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;
}

contains

这个方法的内部实现是依靠indexOf方法来实现的

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

sublist

    public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
// 这里就用到了前面列出的SubList内部类
// 需要注意的是:由sublist方法返回的List,对其操作时会在原List上生效,即它们是同一个元素
return new SubList(this, 0, fromIndex, toIndex);
}

补充方法

此外有四个补充的方法需要注意,这四个方法的参数都是函数式接口的实现类,即可以使用λ表达式

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++) {
// accept的原型为: void accept(T t); 即一个无返回值的函数,也是需要在λ表达式里表示的内容
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}

removeIf

    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];
// test的原型为: boolean test(T t); 返回布尔值,在这里也能看出来,当返回的值为true时,才进行代码块的操作
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;
}

replaceAll

    public void replaceAll(UnaryOperator<E> operator) {
// UnaryOperator 一元运算符
Objects.requireNonNull(operator);
final int expectedModCount = modCount;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
// UnaryOperator<T> 继承自 Function<T,T(R)>
// 其apply 的原型为: R apply(T t); // BinaryOperator<T> 继承自 BiFunction<T,T(U),T(R)>
// 其apply方法原型为: R apply(T t, U u);
elementData[i] = operator.apply((E) elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}

sort

这里的排序是借助于Arrays这个工具类的sort方法来实现的,这里仅作参考

    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++;
}
05-11 11:09