ArrayList源码分析

转载地址:https://blog.csdn.net/ljcitworld/article/details/52041836

全局变量

1. 默认容量

private static final int DEFAULT_CAPACITY = 10;

 

2. 空的对象数组

private static final Object[] EMPTY_ELEMENTDATA = {};

 

3.默认的空数组

  1.  
    // 无参构造函数创建的数组
  2.  
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};


4.存放数据的数组的缓存变量,不可序列化

transient Object[] elementData;


5.元素数量

private int size;

 

构造方法

1.带有容量initialCapacity的构造方法

源码解释:

  1.  
    public ArrayList(int initialCapacity) {
  2.  
    // 如果初始化时ArrayList大小大于0
  3.  
    if (initialCapacity > 0) {
  4.  
    // new一个该大小的object数组赋给elementData
  5.  
    this.elementData = new Object[initialCapacity];
  6.  
    } else if (initialCapacity == 0) { // 如果大小为0
  7.  
    // 将空数组赋给elementData
  8.  
    this.elementData = EMPTY_ELEMENTDATA;
  9.  
    } else { // 小于0
  10.  
    // 则抛出IllegalArgumentException异常
  11.  
    throw new IllegalArgumentException("Illegal Capacity: "+
  12.  
    initialCapacity);
  13.  
    }
  14.  
    }

 

2.不带参数的构造方法

源码解释:

  1.  
    public ArrayList() {
  2.  
    // 直接将空数组赋给elementData
  3.  
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
  4.  
    }

 

3.带参数Collection的构造方法

源码解释:
参数c为一个Collection,Collection的实现类大概有以下几种常用类型:

  • List:元素可以重复的容器
  • Set: 元素不可重复的容器
  • Queue:结构是一个队列,先进先出

这个构造方法的意思是,将一个Collection实现类的对象转换为一个ArrayList,但是c容器装的内容必须为ArrayList装的内容的子类。例如,将一个装了String内容的HashSet转换为装了String内容的ArrayList,使得ArrayList的大小和值数组都是HashSet的大小和值数组。具体实现如下代码,首先调用c(Collection的具体实现类)的toArray方法,具体大家可以看各个实现类的toArray方法,但是大概意思都是将c容器转换为object类型的数组,因为它们的返回值都是object[]。之于下面的两个判断是当得到的elementData的类名不是Object类名的时候或者是长度为0的时候才会执行。

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

 

方法

1.trimToSize()

说明:将ArrayList的容量设置为当前size的大小。首先需要明确一个概念,ArrayList的size就是ArrayList的元素个数,length是ArrayList申请的内容空间长度。ArrayList每次都会预申请多一点空间,以便添加元素的时候不需要每次都进行扩容操作,例如我们的元素个数是10个,它申请的内存空间必定会大于10,即length>size,而这个方法就是把ArrayList的内存空间设置为size,去除没有用到的null值空间。这也就是我们为什么每次在获取数据长度是都是调用list.size()而不是list.length()。

源码解释:首先modCount是从类 java.util.AbstractList 继承的字段,这个字段主要是为了防止在多线程操作的情况下,List发生结构性的变化,什么意思呢?就是防止一个线程正在迭代,另外一个线程进行对List进行remove操作,这样当我们迭代到最后一个元素时,很明显此时List的最后一个元素为空,那么这时modCount就会告诉迭代器,让其抛出异常 ConcurrentModificationException。

如果没有这一个变量,那么系统肯定会报异常ArrayIndexOutOfBoundsException,这样的异常显然不是应该出现的(这些运行时错误都是使用者的逻辑错误导致的,我们的JDK那么高端,不会出现使用错误,我们只抛出使用者造成的错误,而这个错误是设计者应该考虑的),为了避免出现这样的异常,定义了检查。
(引用自:郭无心,详情可以看他在知乎的回答:https://www.zhihu.com/question/24086463/answer/64717159)。

  1.  
    public void trimToSize() {
  2.  
    modCount++;
  3.  
    // 如果size小于length
  4.  
    if (size < elementData.length) {
  5.  
    // 重新将elementData设置大小为size
  6.  
    elementData = (size == 0)
  7.  
    ? EMPTY_ELEMENTDATA
  8.  
    : Arrays.copyOf(elementData, size);
  9.  
    }
  10.  
    }

2.size()

说明:返回ArrayList的大小
源码解释:直接返回size

  1.  
    public int size() {
  2.  
    return size;
  3.  
    }

3.isEmpty()

说明:返回是否为空
源码解释: 直接返回判断size==0

  1.  
    public boolean isEmpty() {
  2.  
    return size == 0;
  3.  
    }

4.indexOf(Object o)

说明:对象o在ArrayList中的下标位置,如果存在返回位置i,不存在返回-1
源码解释:遍历ArrayList的大小,比较o和容器内的元素,若相等,则返回位置i,若遍历完都不相等,返回-1

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

5.contains(Object o)

说明:是否包含对象o
源码解释:调用indexOf()方法得到下标,存在则下标>=0,不存在为-1,即只要比较下标和0的大小即可。

  1.  
    public boolean contains(Object o) {
  2.  
    return indexOf(o) >= 0;
  3.  
    }

6.lastIndexOf(Object o)

说明:返回容器内出现o的最后一个位置

源码解释:从后向前遍历,得到第一个出现对象o的位置,不存在则返回-1

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

7.clone()

说明:返回此 ArrayList 实例的浅表副本。

源码解释:

  1.  
    public Object clone() {
  2.  
    try {
  3.  
    // 调用父类(翻看源码可见是Object类)的clone方法得到一个ArrayList副本
  4.  
    ArrayList<?> v = (ArrayList<?>) super.clone();
  5.  
    // 调用Arrays类的copyOf,将ArrayList的elementData数组赋值给副本的elementData数组
  6.  
    v.elementData = Arrays.copyOf(elementData, size);
  7.  
    v.modCount = 0;
  8.  
    // 返回副本v
  9.  
    return v;
  10.  
    } catch (CloneNotSupportedException e) {
  11.  
    throw new InternalError(e);
  12.  
    }
  13.  
    }

8.toArray()

说明:ArrayList 实例转换为。
源码解释:直接调用Arrays类的copyOf。

  1.  
    public Object[] toArray() {
  2.  
    return Arrays.copyOf(elementData, size);
  3.  
    }

9.toArray(T[] a)

说明:将ArrayList里面的元素赋值到一个数组中去
源码解释:如果a的长度小于ArrayList的长度,直接调用Arrays类的copyOf,返回一个比a数组长度要大的新数组,里面元素就是ArrayList里面的元素;如果a的长度比ArrayList的长度大,那么就调用System.arraycopy,将ArrayList的elementData数组赋值到a数组,然后把a数组的size位置赋值为空。

  1.  
    public <T> T[] toArray(T[] a) {
  2.  
    if (a.length < size)
  3.  
    // Make a new array of a's runtime type, but my contents:
  4.  
    return (T[]) Arrays.copyOf(elementData, size, a.getClass());
  5.  
    System.arraycopy(elementData, 0, a, 0, size);
  6.  
    if (a.length > size)
  7.  
    a[size] = null;
  8.  
    return a;
  9.  
    }

10.rangeCheck(int index)

说明:测试index是否越界
源码解释:

  1.  
    private void rangeCheck(int index) {
  2.  
    // 如果下标超过ArrayList的数组长度
  3.  
    if (index >= size)
  4.  
    // 抛出IndexOutOfBoundsException异常
  5.  
    throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
  6.  
    }

11.get(int index)

说明:获取index位置的元素
源码解释:先检查是否越界,然后返回ArrayList的elementData数组index位置的元素。

  1.  
    public E get(int index) {
  2.  
    // 检查是否越界
  3.  
    rangeCheck(index);
  4.  
    // 返回ArrayList的elementData数组index位置的元素
  5.  
    return elementData(index);
  6.  
    }

12.set(int index, E element)

说明:设置index位置的元素值了element,返回该位置的之前的值
源码解释:

  1.  
    public E set(int index, E element) {
  2.  
    // 检查是否越界
  3.  
    rangeCheck(index);
  4.  
    // 调用elementData(index)获取到当前位置的值
  5.  
    E oldValue = elementData(index);
  6.  
    // 将element赋值到ArrayList的elementData数组的第index位置
  7.  
    elementData[index] = element;
  8.  
    return oldValue;
  9.  
    }

13.ensureCapacityInternal(int minCapacity)

说明:得到最小扩容量
源码解释:

  1.  
    private void ensureCapacityInternal(int minCapacity) {
  2.  
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
  3.  
    // 获取默认的容量和传入参数的较大值
  4.  
    minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
  5.  
    }
  6.  
    ensureExplicitCapacity(minCapacity);
  7.  
    }

14.ensureExplicitCapacity(int minCapacity)

说明:判断是否需要扩容
源码解释:

  1.  
    private void ensureExplicitCapacity(int minCapacity) {
  2.  
    modCount++;
  3.  
    // 如果最小需要空间比elementData的内存空间要大,则需要扩容
  4.  
    if (minCapacity - elementData.length > 0)
  5.  
    grow(minCapacity);
  6.  
    }

15.grow()方法

说明:帮助ArrayList动态扩容的核心方法
源码解释:

  1.  
    // MAX_VALUE为231-1,MAX_ARRAY_SIZE 就是获取Java中int的最大限制,以防止越界
  2.  
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
  3.  
     
  4.  
     
  5.  
    private void grow(int minCapacity) {
  6.  
    // 获取到ArrayList中elementData数组的内存空间长度
  7.  
    int oldCapacity = elementData.length;
  8.  
    // 扩容至原来的1.5倍
  9.  
    int newCapacity = oldCapacity + (oldCapacity >> 1);
  10.  
    // 再判断一下新数组的容量够不够,够了就直接使用这个长度创建新数组,
  11.  
    // 不够就将数组长度设置为需要的长度
  12.  
    if (newCapacity - minCapacity < 0)
  13.  
    newCapacity = minCapacity;
  14.  
    // 判断有没超过最大限制
  15.  
    if (newCapacity - MAX_ARRAY_SIZE > 0)
  16.  
    newCapacity = hugeCapacity(minCapacity);
  17.  
    // 调用Arrays.copyOf方法将elementData数组指向新的内存空间时newCapacity的连续空间
  18.  
    // 并将elementData的数据复制到新的内存空间
  19.  
    elementData = Arrays.copyOf(elementData, newCapacity);
  20.  
    }

16.add(E e)

说明:添加元素e
源码解释:

  1.  
    public boolean add(E e) {
  2.  
    // 扩容
  3.  
    ensureCapacityInternal(size + 1);
  4.  
    // 将e赋值给elementData的size+1的位置。
  5.  
    elementData[size++] = e;
  6.  
    return true;
  7.  
    }

17.add(int index, E element)

说明:在ArrayList的index位置,添加元素element
源码解释:

  1.  
    public void add(int index, E element) {
  2.  
    // 判断index是否越界
  3.  
    rangeCheckForAdd(index);
  4.  
    // 扩容
  5.  
    ensureCapacityInternal(size + 1);
  6.  
    // 将elementData从index位置开始,复制到elementData的index+1开始的连续空间
  7.  
    System.arraycopy(elementData, index, elementData, index + 1,
  8.  
    size - index);
  9.  
    // 在elementData的index位置赋值element
  10.  
    elementData[index] = element;
  11.  
    // ArrayList的大小加一
  12.  
    size++;
  13.  
    }

18.remove(int index)

说明:在ArrayList的移除index位置的元素
源码解释:

  1.  
    public E remove(int index) {
  2.  
    // 判断是否越界
  3.  
    rangeCheck(index);
  4.  
    modCount++;
  5.  
    // 读取旧值
  6.  
    E oldValue = elementData(index);
  7.  
    // 获取index位置开始到最后一个位置的个数
  8.  
    int numMoved = size - index - 1;
  9.  
    if (numMoved > 0)
  10.  
    // 将elementData数组index+1位置开始拷贝到elementData从index开始的空间
  11.  
    System.arraycopy(elementData, index+1, elementData, index,
  12.  
    numMoved);
  13.  
    // 使size-1 ,设置elementData的size位置为空,让GC来清理内存空间
  14.  
    elementData[--size] = null; // clear to let GC do its work
  15.  
    return oldValue;
  16.  
    }

19.remove(Object o)

说明:在ArrayList的移除对象为O的元素,跟indexOf方法思想基本一致
源码解释:

  1.  
    public boolean remove(Object o) {
  2.  
    if (o == null) {
  3.  
    for (int index = 0; index < size; index++)
  4.  
    if (elementData[index] == null) {
  5.  
    fastRemove(index);
  6.  
    return true;
  7.  
    }
  8.  
    } else {
  9.  
    for (int index = 0; index < size; index++)
  10.  
    if (o.equals(elementData[index])) {
  11.  
    fastRemove(index);
  12.  
    return true;
  13.  
    }
  14.  
    }
  15.  
    return false;
  16.  
    }

20.clear()

说明:设置全部元素为null值,并设置size为0。
源码解释:可见clear操作并不是从空间内删除,只是设置为null值,等待垃圾回收机制来回收而已,把size设置为0,以便我们不会浏览到null值的内存空间。

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

21.addAll(Collection<? extends E> c)

说明:将Collection c的全部元素添加到ArrayList中
源码解释:

  1.  
    public boolean addAll(Collection<? extends E> c) {
  2.  
    // 将c转换为数组a
  3.  
    Object[] a = c.toArray();
  4.  
    // 获取a占的内存空间长度赋值给numNew
  5.  
    int numNew = a.length;
  6.  
    // 扩容至size + numNew
  7.  
    ensureCapacityInternal(size + numNew); // Increments modCount
  8.  
    // 将a的第0位开始拷贝至elementData的size位开始,拷贝长度为numNew
  9.  
    System.arraycopy(a, 0, elementData, size, numNew);
  10.  
    // 将size增加numNew
  11.  
    size += numNew;
  12.  
    // 如果c为空,返回false,c不为空,返回true
  13.  
    return numNew != 0;
  14.  
    }

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

说明:从第index位开始,将c全部拷贝到ArrayList
源码解释:

  1.  
    public boolean addAll(int index, Collection<? extends E> c) {
  2.  
    // 判断index大于size或者是小于0,如果是,则抛出IndexOutOfBoundsException异常
  3.  
    rangeCheckForAdd(index);
  4.  
    // 将c转换为数组a
  5.  
    Object[] a = c.toArray();
  6.  
    int numNew = a.length;
  7.  
    // 扩容至size + numNew
  8.  
    ensureCapacityInternal(size + numNew); // Increments modCount
  9.  
    // 获取需要添加的个数
  10.  
    int numMoved = size - index;
  11.  
    if (numMoved > 0)
  12.  
    System.arraycopy(elementData, index, elementData, index + numNew,
  13.  
    numMoved);
  14.  
    System.arraycopy(a, 0, elementData, index, numNew);
  15.  
    size += numNew;
  16.  
    return numNew != 0;
  17.  
    }

24.batchRemove(Collection<?> c, boolean complement)

说明:根据complement值,将ArrayList中包含c中元素的元素删除或者保留
源码解释:

  1.  
    private boolean batchRemove(Collection<?> c, boolean complement) {
  2.  
    final Object[] elementData = this.elementData;
  3.  
    // 定义一个w,一个r,两个同时右移
  4.  
    int r = 0, w = 0;
  5.  
    boolean modified = false;
  6.  
    try {
  7.  
    // r先右移
  8.  
    for (; r < size; r++)
  9.  
    // 如果c中不包含elementData[r]这个元素
  10.  
    if (c.contains(elementData[r]) == complement)
  11.  
    // 则直接将r位置的元素赋值给w位置的元素,w自增
  12.  
    elementData[w++] = elementData[r];
  13.  
    } finally {
  14.  
    // 防止抛出异常导致上面r的右移过程没完成
  15.  
    if (r != size) {
  16.  
    // 将r未右移完成的位置的元素赋值给w右边位置的元素
  17.  
    System.arraycopy(elementData, r,
  18.  
    elementData, w,
  19.  
    size - r);
  20.  
    // 修改w值增加size-r
  21.  
    w += size - r;
  22.  
    }
  23.  
    if (w != size) {
  24.  
    // 如果有被覆盖掉的元素,则将w后面的元素都赋值为null
  25.  
    for (int i = w; i < size; i++)
  26.  
    elementData[i] = null;
  27.  
    modCount += size - w;
  28.  
    // 修改size为w
  29.  
    size = w;
  30.  
    modified = true;
  31.  
    }
  32.  
    }
  33.  
    return modified;
  34.  
    }

25.removeAll(Collection<?> c)

说明:ArrayList移除c中的所有元素
源码解释:

  1.  
    public boolean removeAll(Collection<?> c) {
  2.  
    // 如果c为空,则抛出空指针异常
  3.  
    Objects.requireNonNull(c);
  4.  
    // 调用batchRemove移除c中的元素
  5.  
    return batchRemove(c, false);
  6.  
    }

26.retainAll(Collection<?> c)

说明:和removeAll相反,仅保留c中所有的元素

源码解释:

  1.  
    public boolean retainAll(Collection<?> c) {
  2.  
    Objects.requireNonNull(c);
  3.  
    // 调用batchRemove保留c中的元素
  4.  
    return batchRemove(c, true);
  5.  
    }

27.iterator()

说明:返回一个Iterator对象,Itr为ArrayList的一个内部类,其实现了Iterator<E>接口

代码解释:

  1.  
    public Iterator<E> iterator() {
  2.  
    return new Itr();
  3.  
    }

28.listIterator()

说明:返回一个ListIterator对象,ListItr为ArrayList的一个内部类,其实现了ListIterator<E> 接口
源码解释:

  1.  
    public ListIterator<E> listIterator() {
  2.  
    return new ListItr(0);
  3.  
    }

29.listIterator(int index)

说明:返回一个从index开始的ListIterator对象
源码解释:

  1.  
    public ListIterator<E> listIterator(int index) {
  2.  
    if (index < 0 || index > size)
  3.  
    throw new IndexOutOfBoundsException("Index: "+index);
  4.  
    return new ListItr(index);
  5.  
    }

30.subList(int fromIndex, int toIndex)

说明:根据两个参数,获取到一个子序列
源码解释:

  1.  
    public List<E> subList(int fromIndex, int toIndex) {
  2.  
    // 检查异常
  3.  
    subListRangeCheck(fromIndex, toIndex, size);
  4.  
    // 调用SubList类的构造方法
  5.  
    return new SubList(this, 0, fromIndex, toIndex);
  6.  
    }

内部类

    1.  
      (1)private class Itr implements Iterator<E>
    2.  
      (2)private class ListItr extends Itr implements ListIterator<E>
    3.  
      (3)private class SubList extends AbstractList<E> implements RandomAccess
    4.  
      (4)static final class ArrayListSpliterator<E> implements Spliterator<E>
    5.  

posted @ 2018-07-18 14:49  萌的一波  阅读(283)  评论(0编辑  收藏  举报