初始化
无参构造方法
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}
DEFAULTCAPACITY_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);}}
直接按照初始容量构造 elementData 数组
带有初始数据的构造方法
public ArrayList(Collection<? extends E> c) {Object[] a = c.toArray();if ((size = a.length) != 0) {if (c.getClass() == ArrayList.class) {elementData = a;} else {elementData = Arrays.copyOf(a, size, Object[].class);}} else {// replace with empty array.elementData = EMPTY_ELEMENTDATA;}}
原始数据是个 ArrayList ,则直接赋值,此处赋值不会产生关联,因为 ArrayList 的 toArray 方法是做了 copy 数组数据;其他情况也是 copy 数组数据
size()
isEmpty()
contains(Object o)
判断是否包含某个元素,判断 indexOf(o) >= 0,主要看下 indexOf(o) 的实现
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;}
add(E e)
增加元素,直接增加到数组末尾
public boolean add(E e) {ensureCapacityInternal(size + 1); // Increments modCount!!elementData[size++] = e;return true;}
主要是 ensureCapacityInternal 扩容逻辑
private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);}
calculateCapacity 主要是再次计算 minCapacity,如果之前是无参构造 elementData 为空数组时,则取Math.max(DEFAULT_CAPACITY, minCapacity),DEFAULT_CAPACITY = 10,需要扩容时调用 grow 方法,elementData 时存储数据的,但是不一定满,所以只有在 elementData 容量不足时才扩容
private void grow(int minCapacity) {// overflow-conscious codeint 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);}
新的容量,扩展为原来容量的1.5倍,如果大于ArrayList 可以容许的最大容量,则设置为最大容量,最终利用Arrays.copy 进行扩容,生成一个新容量的新数组
add(int index, E element)
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++;}
先check index 位置,不能大于size & 小于0,确定容量后,根据 index 移动数组数据,然后在 index 位置插入新数据
addAll(Collection<? extends E> c)
public boolean addAll(Collection<? extends E> c) {Object[] a = c.toArray();int numNew = a.length;ensureCapacityInternal(size + numNew); // Increments modCountSystem.arraycopy(a, 0, elementData, size, numNew);size += numNew;return numNew != 0;}
扩容确定,直接把 c 数组数据 copy 到 elementData 里
addAll(int index, Collection<? extends E> c)
public boolean addAll(int index, Collection<? extends E> c) {rangeCheckForAdd(index);Object[] a = c.toArray();int numNew = a.length;ensureCapacityInternal(size + numNew); // Increments modCountint 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;}
扩容确定,判断如果插入在中间,要先 copy原数据预留出位置,然后用 c 数据填充这些位置
remove(int index)
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 workreturn oldValue;}
先取出数据,供后面返回,然后数据前移覆盖,对最后一个数据置空,—size 很巧妙,即解决了 length 和 index 差1的问题,也完成了 size 的改变
remove(Object o)
与 remove(int index) 类似,只是先循环比较找到 index,然后再执行 remove(int index) 的逻辑
removeAll(Collection<?> c)
执行了 batchRemove(c, false) 逻辑,主要看下这个
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 workfor (int i = w; i < size; i++)elementData[i] = null;modCount += size - w;size = w;modified = true;}}return modified;}
遍历,发现不在 c 里的就移动到数组前部,中间考虑了下发生异常的异常,最后把多余的数据移除掉
clear()
public void clear() {modCount++;// clear to let GC do its workfor (int i = 0; i < size; i++)elementData[i] = null;size = 0;}
get(int index)
set(int index, E element)
直接根据数据 index 位置 set 数据
