Java集合系列02之ArrayList源码分析

系列文章

  • Java集合系列01之概览
  • Java集合系列02之ArrayList源码分析
  • Java集合系列03之LinkedList源码分析
  • Java集合系列04之fail-fast机制分析
  • Java集合系列05之Vector&Stack源码分析及List总结
  • Java集合系列06之Map接口概览
  • Java集合系列07之HashMap源码分析
  • Java集合系列08之WeakHashMap源码分析
  • Java集合系列09之TreeMap源码分析
  • Java集合系列10之Hashtable源码分析

前言

本文开始分析具体集合的源码和实现原理,首先来看ArrayListArrayList可以理解为一个动态数组,与普通数组相比,它的容量能动态增长。其定义如下:

public class ArrayList extends AbstractList
        implements List, RandomAccess, Cloneable, java.io.Serializable

可以看到ArrayList继承了AbstractList类,实现了ListRandomAccessCloneablejava.io.Serializable四个接口。

上文提到,AbstractList类提供了大部分List接口的实现,帮助我们减少了实现List接口的工作。

RandomAccess接口是List实现所使用的标记接口,表明List支持快速随机访问功能(就是通过索引获取元素)。

实现Cloneable接口表明覆盖了Clone()函数,能被克隆,实现java.io.Serializable接口表明ArrayList支持序列化。

本文源码分析基于jdk 1.8.0_121

继承关系

ArrayList的继承关系

java.lang.Object
  |___java.util.AbstractCollection
      |___ java.util.AbstractList
          |___ java.util.ArrayList
所有已实现的接口:
Serializable, Cloneable, Iterable, Collection, List, RandomAccess
直接已知子类:
AttributeList, RoleList, RoleUnresolvedList

关系图

Java集合系列02之ArrayList源码分析_第1张图片
ArrayList关系图

ArrayList的两个成员elementDatasize比较重要:

  • elementDataObject类型的数组,保存了ArrayList的数据,是ArrayList的底层实现,它是个动态数组,在添加数据过程中不断扩展容量,最大容量为Integer.MAX_VALUE - 8;容量的增长方式在源码中具体再分析
  • size是当前动态数组的实际大小

构造函数

public ArrayList() {}       // 默认构造函数  
public ArrayList(int initialCapacity) {} // 构造一个具有特定初始容量的ArrayList
public ArrayList(Collection c) {} // 创建一个包含Collection的ArrayList

以上三种构造函数在不同JDK版本之间也略有差异,但思想或者做的工作都基本一致。
public ArrayList()JDK1.8.0_121中令elementData为一个空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA,而此版本中还存在另一个空数组成员EMPTY_ELEMENTDATA,此两者的区别是用来区分ArrayList添加第一个元素时容量要扩张多少。在之前的JDK版本中默认构造函数是直接初始化一个容量为10的数组。 (具体哪一版本开始出现这一区别不知道)
public ArrayList(int initialCapacity)构造一个指定初始容量的空列表,当initialCapacity为0时,令elementDataEMPTY_ELEMENTDATA
public ArrayList(Collection c)构造一个包含Collection的元素的列表,这些元素按照该Collection的迭代器返回它们的顺序排列的,先将Collection转为数组,再将数组拷贝给elementData

API

// Collection中定义的API(部分)
boolean             add(E object)
boolean             addAll(Collection collection)
void                clear()
boolean             contains(Object object)
boolean             containsAll(Collection collection)
boolean             equals(Object object)
int                 hashCode()
boolean             isEmpty()
Iterator         iterator()
boolean             remove(Object object)
boolean             removeAll(Collection collection)
boolean             retainAll(Collection collection)
int                 size()
 T[]             toArray(T[] array)
Object[]            toArray()
// AbstractList API(部分)
void                add(int index, E element) 
boolean             addAll(int index, Collection c)
E                   get(int index)
int                 indexOf(Object o)
ListIterator     listIterator()
ListIterator     listIterator(final int index)
E                   remove(int index)
E                   set(int index, E element)
List             subList(int fromIndex, int toIndex) 
// ArrayList API(部分)
Object              clone()
void                ensureCapacity(int minCapacity)
void                trimToSize()
void                removeRange(int fromIndex, int toIndex)

源码分析

成员对象

// List默认容量
private static final int DEFAULT_CAPACITY = 10;

// 空数组
private static final Object[] EMPTY_ELEMENTDATA = {};

// 空数组,使用默认构造函数创建,则默认对象内容默认是该值
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

// 保存ArrayList中数据的数组,transient表示不参与序列化
transient Object[] elementData;

// 实际容量大小
private int size;

// 数组最大值
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

构造函数

// 带初始容量的构造函数
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);
   }
}

// 默认构造函数   
public ArrayList() {
   this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

// 带Collection对象的构造函数
public ArrayList(Collection 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 void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}

确定容量

// 判断待设置的最小容量minCapacity和默认容量大小
// minCapacity大于minExpand时才扩张容量
public void ensureCapacity(int minCapacity) {
    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)? 0:DEFAULT_CAPACITY;

    if (minCapacity > minExpand) {
        ensureExplicitCapacity(minCapacity);
    }
}

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);
}

// 修改次数+1,如果minCapacity大于数组长度,则扩张容量
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

// 设置新容量为(原始容量x3)/2
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);
}

// 当minCapacity超出Integer.MAX_VALUE时,minCapacity变为负数,抛出异常
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

增加元素

// 添加元素e到ArrayList
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!!
   // 把原数组index索引开始后的所有元素向后移动一个位置
   System.arraycopy(elementData, index, elementData, index + 1,
        size - index);
   elementData[index] = element;
   size++;
}

// 集合c追加到ArrayList中
public boolean addAll(Collection c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount
    // 将集合c转换为数组后复制到elementData中
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}

// 从位置index开始,将集合c添加到ArrayList中
public boolean addAll(int index, Collection c) {
    rangeCheckForAdd(index);

    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount

    int numMoved = size - index;
    // 先在elementData中空出长度为集合c中元素个数的位置
    if (numMoved > 0)
        System.arraycopy(elementData, index, elementData, index + numNew,
                         numMoved);
    
    // 复制集合元素到elementData中
    System.arraycopy(a, 0, elementData, index, numNew);
    size += numNew;
    return numNew != 0;  
}

toArray

// 转化为ArrayList的Object数组
public Object[] toArray() {
    return Arrays.copyOf(elementData, size);
}
    
// 返回T类型的数组
public  T[] toArray(T[] a) {
    // 如果数组a的大小小于ArrayList的实际大小
    // 则新建一个数组(T[])数组,将ArrayList中元素全部拷贝到新数组中
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    // 若数组a的大小大于ArrayList的实际大小
    // 则将ArrayList中全部元素拷贝到数组a中
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

调用toArray方法有以下两种:

java.lang.Integer[] obj = (java.lang.Integer[])list.toArray();
java.lang.Integer[] obj1 = list.toArray(new Integer[0]);

调用第一种方法会抛出“java.lang.ClassCastException”异常,调用 toArray(T[] contents) 能正常返回 T[]
这是因为将Object[]转换为的Integer[]则会抛出“java.lang.ClassCastException”异常,因为Java不支持向下转型。

设置元素

// 设置index处元素值,并返回旧值
public E set(int index, E element) {
    rangeCheck(index);

    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

读取元素

// 获取index位置的元素值
public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}

删除元素

// 删除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 work

    return oldValue;
}

// 删除指定元素
public boolean remove(Object o) {
    // 判断o是否为null
    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;
}

// 快速删除第index个元素
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
}

// 删除一定索引范围内元素值
protected void removeRange(int fromIndex, int toIndex) {
    modCount++;
    int numMoved = size - toIndex;
    System.arraycopy(elementData, toIndex, elementData, fromIndex,
                     numMoved);

    // clear to let GC do its work
    int newSize = size - (toIndex-fromIndex);
    for (int i = newSize; i < size; i++) {
        elementData[i] = null;
    }
    size = newSize;
}

// 删除所有元素
public boolean removeAll(Collection c) {
    Objects.requireNonNull(c);
    return batchRemove(c, false);
}

序列化

// 将ArrayList的“容量,所有的元素值”都写入到输出流中
private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException{
    // Write out element count, and any hidden stuff
    int expectedModCount = modCount;
    s.defaultWriteObject();

    // 写入数组容量
    s.writeInt(size);

    // 写入所有元素
    for (int i=0; i

遍历方式

  • 迭代器遍历,即通过Iterator遍历
Iterator iter = list.iterator();
while(iter.hasNext()) {
    iter.next();
}
  • 随机访问,索引值
for (int i=0; i
  • foreach循环
for (Integer integ:list) {
    ;
}

通过比较以上三种遍历方式,我们发现通过随机访问方式效率最高,而另两种方式效率都不高。

参考内容

  • Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
  • ArrayList 的实现原理

你可能感兴趣的:(Java集合系列02之ArrayList源码分析)