属性

DEFAULT_CAPACITY,默认初始化容量10
size 表示当前数组大小 非线程安全
modCount 统计当前数组被修改的版本次数,数据结构有变动就会+1

  1. /**
  2. * 默认初始化容量
  3. */
  4. private static final int DEFAULT_CAPACITY = 10;
  5. /**
  6. * 如果自定义容量为0,则会默认用它来初始化ArrayList。或者用于空数组替换。
  7. */
  8. private static final Object[] EMPTY_ELEMENTDATA = {};
  9. /**
  10. * 如果没有自定义容量,则会使用它来初始化ArrayList。或者用于空数组比对。
  11. */
  12. private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
  13. /**
  14. * 这就是ArrayList底层用到的数组
  15. * 非私有,以简化嵌套类访问
  16. * transient 在已经实现序列化的类中,不允许某变量序列化
  17. */
  18. transient Object[] elementData;
  19. /**
  20. * 实际ArrayList集合大小
  21. */
  22. private int size;
  23. /**
  24. * 可分配的最大容量
  25. */
  26. private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

构造函数

默认构造函数

初始化赋值的是一个空数组,当执行增加元素操作,才会分配空间大小,即向数组中添加第一个元素时,数组容量扩为10。

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

自定义大小

根据initialCapacity 数值初始化一个空数组,如果值为0,则初始化一个空数组:

  1. /**
  2. * 根据initialCapacity 初始化一个空数组
  3. */
  4. public ArrayList(int initialCapacity) {
  5. if (initialCapacity > 0) {
  6. this.elementData = new Object[initialCapacity];
  7. } else if (initialCapacity == 0) {
  8. this.elementData = EMPTY_ELEMENTDATA;
  9. } else {
  10. throw new IllegalArgumentException("Illegal Capacity: "+
  11. initialCapacity);
  12. }
  13. }

集合构造

通过集合做参数的形式初始化:如果集合为空,则初始化为空数组,如果

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

增加

add(E e)

指定的元素追加到此列表的末尾。

  • 当我们要 add 进第1个元素到 ArrayList 时,elementData.length 为0 (因为还是一个空的 list),因为执行了 ensureCapacityInternal() 方法 ,所以 minCapacity 此时为10。此时,minCapacity - elementData.length > 0成立,所以会进入 grow(minCapacity) 方法。
  • 当add第2个元素时,minCapacity 为2,此时e lementData.length(容量)在添加第一个元素后扩容成 10 了。此时,minCapacity - elementData.length > 0不成立,所以不会进入 (执行)grow(minCapacity) 方法。
  • 添加第3、4···到第10个元素时,依然不会执行grow方法,数组容量都为10。
  • 直到添加第11个元素,minCapacity(为11)比elementData.length(为10)要大。进入grow方法进行扩容。
    1. /**
    2. * 在数组末尾添加元素
    3. */
    4. public boolean add(E e) {
    5. ensureCapacityInternal(size + 1); // Increments modCount!!
    6. elementData[size++] = e;
    7. return true;
    8. }

    ensureCapacityInternal()

    注意参数是size+1,size+1代表的含义是:
  1. 如果集合添加元素成功后,集合中的实际元素个数。
  2. 为了确保扩容不会出现错误。

假如不加一处理,如果默认size是0,则0+0>>1还是0。如果size是1,则1+1>>1还是1。在1.8版本后,默认ArrayList arrayList = new ArrayList();后,size应该是0.所以,size+1对扩容来讲很必要.

  1. private void ensureCapacityInternal(int minCapacity) {
  2. ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
  3. }

calculateCapacity

计算容量:如果elementData是空,则返回默认容量10和size+1的最大值,否则返回size+1

  1. private static int calculateCapacity(Object[] elementData, int minCapacity) {
  2. if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
  3. return Math.max(DEFAULT_CAPACITY, minCapacity);
  4. }
  5. return minCapacity;
  6. }

ensureExplicitCapacity

判断是否需要扩容,如果size+1 > elementData.length证明数组已经放满,则增加容量,调用grow()

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

增加容量:默认1.5倍扩容。

  1. 获取当前数组长度=>oldCapacity
  2. oldCapacity>>1 表示将oldCapacity右移一位(位运算),相当于除2。再加上1,相当于新容量扩容1.5倍。
  3. 如果newCapacity<mincapacity,则newcapacity mincapacity="size+1=2" elementdata="1" newcapacity="1+1""" style="font-size: inherit;color: inherit;line-height: inherit;">&gt;1=1</mincapacity,则newcapacity>,1&lt;2所以如果不处理该情况,扩容将不能正确完成。
  4. 如果新容量比最大值还要大,则将新容量赋值为VM要求最大值。
  5. 将elementData拷贝到一个新的容量中。

    grow

    oldCapacity为旧容量,newCapacity为新容量
    将oldCapacity 右移一位,其效果相当于oldCapacity /2,整句运算式的结果就是将新容量更新为旧容量的1.5倍,如果新容量大于 MAX_ARRAY_SIZE,进入(执行) hugeCapacity() 方法来比较 minCapacity 和 MAX_ARRAY_SIZE,
    如果minCapacity大于最大容量,则新容量则为Integer.MAX_VALUE,否则,新容量大小则为 MAX_ARRAY_SIZE 即为 Integer.MAX_VALUE - 8
    扩容探究
  • 当add第1个元素时,oldCapacity 为0,经比较后第一个if判断成立,newCapacity = minCapacity(为10)。但是第二个if判断不会成立,即newCapacity 不比 MAX_ARRAY_SIZE大,则不会进入 hugeCapacity 方法。数组容量为10,add方法中 return true,size增为1。
  • 当add第11个元素进入grow方法时,newCapacity为15,比minCapacity(为11)大,第一个if判断不成立。新容量没有大于数组最大size,不会进入hugeCapacity方法。数组容量扩为15,add方法中return true,size增为11。
  • 以此类推······ ```java /**
    • 要分配的最大数组大小 */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; private void grow(int minCapacity) { // overflow-conscious code int 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); }

private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); //对minCapacity和MAX_ARRAY_SIZE进行比较 //若minCapacity大,将Integer.MAX_VALUE作为新数组的大小 //若MAX_ARRAY_SIZE大,将MAX_ARRAY_SIZE作为新数组的大小 //MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }

  1. ---
  2. <a name="PW4PN"></a>
  3. #### 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++; }

  1. rangeCheckForAdd()是越界异常检测方法。`ensureCapacityInternal()`之前有讲,着重说一下`System.arrayCopy`方法:

public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

  1. 代码解释:
  2. - Object src : 原数组
  3. - int srcPos : 从元数据的起始位置开始
  4. - Object dest : 目标数组
  5. - int destPos : 目标数组的开始起始位置
  6. - int length : copy的数组的长度
  7. ```java
  8. int[] srcArray = new int[]{2, 4, 1, 2, 3, 4, 9, 10, 15, 50};
  9. int[] destArray = new int[5];
  10. System.arraycopy(srcArray, 0, destArray, 1, 4);
  11. for (int i = 0; i < destArray.length; i++) {
  12. System.out.println(destArray[i]);
  13. }

ensureCapacity

在 add 大量元素之前用 ensureCapacity 方法,以减少增量重新分配的次数

  1. /**
  2. 如有必要,增加此 ArrayList 实例的容量,以确保它至少可以容纳由minimum capacity参数指定的元素数。
  3. *
  4. * @param minCapacity 所需的最小容量
  5. */
  6. public void ensureCapacity(int minCapacity) {
  7. int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
  8. // any size if not default element table
  9. ? 0
  10. // larger than default for default empty table. It's already
  11. // supposed to be at default size.
  12. : DEFAULT_CAPACITY;
  13. if (minCapacity > minExpand) {
  14. ensureExplicitCapacity(minCapacity);
  15. }
  16. }

ArrayList 添加大量元素之前最好先使用ensureCapacity 方法,以减少增量重新分配的次数

  1. public class EnsureCapacityTest {
  2. public static void main(String[] args) {
  3. ArrayList<Object> list = new ArrayList<Object>();
  4. final int N = 10000000;
  5. long startTime = System.currentTimeMillis();
  6. for (int i = 0; i < N; i++) {
  7. list.add(i);
  8. }
  9. long endTime = System.currentTimeMillis();
  10. System.out.println("使用ensureCapacity方法前:"+(endTime - startTime));
  11. list = new ArrayList<Object>();
  12. long startTime1 = System.currentTimeMillis();
  13. list.ensureCapacity(N);
  14. for (int i = 0; i < N; i++) {
  15. list.add(i);
  16. }
  17. long endTime1 = System.currentTimeMillis();
  18. System.out.println("使用ensureCapacity方法后:"+(endTime1 - startTime1));
  19. }
  20. }

删除

remove(int index)

删除指定下标的元素。

  1. public E remove(int index) {
  2. // 检测index是否合法
  3. rangeCheck(index);
  4. // 数据结构修改次数
  5. modCount++;
  6. E oldValue = elementData(index);
  7. // 记住这个算法
  8. int numMoved = size - index - 1;
  9. if (numMoved > 0)
  10. System.arraycopy(elementData, index+1, elementData, index,
  11. numMoved);
  12. elementData[--size] = null; // clear to let GC do its work
  13. return oldValue;
  14. }

根据对象删除

  1. public boolean remove(Object var1) {
  2. int var2;
  3. if (var1 == null) {
  4. for(var2 = 0; var2 < this.size; ++var2) {
  5. if (this.elementData[var2] == null) {
  6. this.fastRemove(var2);
  7. return true;
  8. }
  9. }
  10. } else {
  11. for(var2 = 0; var2 < this.size; ++var2) {
  12. if (var1.equals(this.elementData[var2])) {
  13. this.fastRemove(var2);
  14. return true;
  15. }
  16. }
  17. }
  18. return false;
  19. }
  20. private void fastRemove(int var1) {
  21. ++this.modCount;
  22. int var2 = this.size - var1 - 1;
  23. if (var2 > 0) {
  24. System.arraycopy(this.elementData, var1 + 1, this.elementData, var1, var2);
  25. }
  26. this.elementData[--this.size] = null;
  27. }

修改

set(int index,E element)

  1. public E set(int index, E element) {
  2. rangeCheck(index);
  3. E oldValue = elementData(index);
  4. elementData[index] = element;
  5. return oldValue;
  6. }

查找

indexOf(Object o)

根据Object对象获取数组中的索引值。如果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. }

get(int index)

返回指定下标处的元素的值。rangeCheck(index)会检测index值是否合法,如果合法则返回索引对应的值。

  1. public E get(int index) {
  2. rangeCheck(index);
  3. return elementData(index);
  4. }