初始化

无参构造方法

  1. public ArrayList() {
  2. this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
  3. }

DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {} ,是个空数组

带有初始容量的构造方法

  1. public ArrayList(int initialCapacity) {
  2. if (initialCapacity > 0) {
  3. this.elementData = new Object[initialCapacity];
  4. } else if (initialCapacity == 0) {
  5. this.elementData = EMPTY_ELEMENTDATA;
  6. } else {
  7. throw new IllegalArgumentException("Illegal Capacity: "+
  8. initialCapacity);
  9. }
  10. }

直接按照初始容量构造 elementData 数组

带有初始数据的构造方法

  1. public ArrayList(Collection<? extends E> c) {
  2. Object[] a = c.toArray();
  3. if ((size = a.length) != 0) {
  4. if (c.getClass() == ArrayList.class) {
  5. elementData = a;
  6. } else {
  7. elementData = Arrays.copyOf(a, size, Object[].class);
  8. }
  9. } else {
  10. // replace with empty array.
  11. elementData = EMPTY_ELEMENTDATA;
  12. }
  13. }

原始数据是个 ArrayList ,则直接赋值,此处赋值不会产生关联,因为 ArrayList 的 toArray 方法是做了 copy 数组数据;其他情况也是 copy 数组数据

size()

有个变量 size 存储,每次有变动时都更新这个值

isEmpty()

判断 size == 0

contains(Object o)

判断是否包含某个元素,判断 indexOf(o) >= 0,主要看下 indexOf(o) 的实现

  1. public int indexOf(Object o) {
  2. if (o == null) {
  3. for (int i = 0; i < size; i++)
  4. if (elementData[i]==null)
  5. return i;
  6. } else {
  7. for (int i = 0; i < size; i++)
  8. if (o.equals(elementData[i]))
  9. return i;
  10. }
  11. return -1;
  12. }

很简单,就是循环遍历比较

add(E e)

增加元素,直接增加到数组末尾

  1. public boolean add(E e) {
  2. ensureCapacityInternal(size + 1); // Increments modCount!!
  3. elementData[size++] = e;
  4. return true;
  5. }

主要是 ensureCapacityInternal 扩容逻辑

  1. private void ensureCapacityInternal(int minCapacity) {
  2. ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
  3. }
  4. private void ensureExplicitCapacity(int minCapacity) {
  5. modCount++;
  6. // overflow-conscious code
  7. if (minCapacity - elementData.length > 0)
  8. grow(minCapacity);
  9. }

calculateCapacity 主要是再次计算 minCapacity,如果之前是无参构造 elementData 为空数组时,则取Math.max(DEFAULT_CAPACITY, minCapacity),DEFAULT_CAPACITY = 10,需要扩容时调用 grow 方法,elementData 时存储数据的,但是不一定满,所以只有在 elementData 容量不足时才扩容

  1. private void grow(int minCapacity) {
  2. // overflow-conscious code
  3. int oldCapacity = elementData.length;
  4. int newCapacity = oldCapacity + (oldCapacity >> 1);
  5. if (newCapacity - minCapacity < 0)
  6. newCapacity = minCapacity;
  7. if (newCapacity - MAX_ARRAY_SIZE > 0)
  8. newCapacity = hugeCapacity(minCapacity);
  9. // minCapacity is usually close to size, so this is a win:
  10. elementData = Arrays.copyOf(elementData, newCapacity);
  11. }

新的容量,扩展为原来容量的1.5倍,如果大于ArrayList 可以容许的最大容量,则设置为最大容量,最终利用Arrays.copy 进行扩容,生成一个新容量的新数组

add(int index, E element)

  1. public void add(int index, E element) {
  2. rangeCheckForAdd(index);
  3. ensureCapacityInternal(size + 1); // Increments modCount!!
  4. System.arraycopy(elementData, index, elementData, index + 1,
  5. size - index);
  6. elementData[index] = element;
  7. size++;
  8. }

先check index 位置,不能大于size & 小于0,确定容量后,根据 index 移动数组数据,然后在 index 位置插入新数据

addAll(Collection<? extends E> c)

  1. public boolean addAll(Collection<? extends E> c) {
  2. Object[] a = c.toArray();
  3. int numNew = a.length;
  4. ensureCapacityInternal(size + numNew); // Increments modCount
  5. System.arraycopy(a, 0, elementData, size, numNew);
  6. size += numNew;
  7. return numNew != 0;
  8. }

扩容确定,直接把 c 数组数据 copy 到 elementData 里

addAll(int index, Collection<? extends E> c)

  1. public boolean addAll(int index, Collection<? extends E> c) {
  2. rangeCheckForAdd(index);
  3. Object[] a = c.toArray();
  4. int numNew = a.length;
  5. ensureCapacityInternal(size + numNew); // Increments modCount
  6. int numMoved = size - index;
  7. if (numMoved > 0)
  8. System.arraycopy(elementData, index, elementData, index + numNew,
  9. numMoved);
  10. System.arraycopy(a, 0, elementData, index, numNew);
  11. size += numNew;
  12. return numNew != 0;
  13. }

扩容确定,判断如果插入在中间,要先 copy原数据预留出位置,然后用 c 数据填充这些位置

remove(int index)

  1. public E remove(int index) {
  2. rangeCheck(index);
  3. modCount++;
  4. E oldValue = elementData(index);
  5. int numMoved = size - index - 1;
  6. if (numMoved > 0)
  7. System.arraycopy(elementData, index+1, elementData, index,
  8. numMoved);
  9. elementData[--size] = null; // clear to let GC do its work
  10. return oldValue;
  11. }

先取出数据,供后面返回,然后数据前移覆盖,对最后一个数据置空,—size 很巧妙,即解决了 length 和 index 差1的问题,也完成了 size 的改变

remove(Object o)

与 remove(int index) 类似,只是先循环比较找到 index,然后再执行 remove(int index) 的逻辑

removeAll(Collection<?> c)

执行了 batchRemove(c, false) 逻辑,主要看下这个

  1. private boolean batchRemove(Collection<?> c, boolean complement) {
  2. final Object[] elementData = this.elementData;
  3. int r = 0, w = 0;
  4. boolean modified = false;
  5. try {
  6. for (; r < size; r++)
  7. if (c.contains(elementData[r]) == complement)
  8. elementData[w++] = elementData[r];
  9. } finally {
  10. // Preserve behavioral compatibility with AbstractCollection,
  11. // even if c.contains() throws.
  12. if (r != size) {
  13. System.arraycopy(elementData, r,
  14. elementData, w,
  15. size - r);
  16. w += size - r;
  17. }
  18. if (w != size) {
  19. // clear to let GC do its work
  20. for (int i = w; i < size; i++)
  21. elementData[i] = null;
  22. modCount += size - w;
  23. size = w;
  24. modified = true;
  25. }
  26. }
  27. return modified;
  28. }

遍历,发现不在 c 里的就移动到数组前部,中间考虑了下发生异常的异常,最后把多余的数据移除掉

clear()

  1. public void clear() {
  2. modCount++;
  3. // clear to let GC do its work
  4. for (int i = 0; i < size; i++)
  5. elementData[i] = null;
  6. size = 0;
  7. }

简单的遍历,置空,等待回收

get(int index)

直接按数据 index 位置读取

set(int index, E element)

直接根据数据 index 位置 set 数据