首页 > 代码库 > ArrayList源码分析

ArrayList源码分析

1.ArrayList的特点:

     线程不安全

     查找速度快

     增删速度慢

      数组结构


ArrayList源码分析:

2.ArrayList的继承和实现接口关系

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

 可以看到ArrayList继承了AbstractList<E>类,实现了implements List<E>, RandomAccess, Cloneable, java.io.Serializable接口;


AbstractList<E>类的继承实现关系如下了public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> ,AbstractList<E>继承了AbstractCollection类,查看AbstractList<E>类的源码,我们可以发现

AbstractList<E>实现了部分的方法,又有一部分的方法是抽象的方法;


当我们看AbstractCollection<E> 源码的时候,可以发现public abstract class AbstractCollection<E> implements Collection<E>,终于AbstractCollection<E> 实现了Collection<E>接口,ArrayList和Collection<E>终于挂上关系了,

AbstractCollection<E> 也实现了部分方法,有部分方法是抽象方法。


从这么多继承和实现关系,可以看出这些类的实现都是分层的,那个类做什么事情。


由于ArrayList类的方法众多,我就不每个都介绍了,下面主要介绍下常用的方法和属性。想理解更多地可以直接看源代码,有很清楚的介绍


3.ArrayList的基本属性

   private static final long serialVersionUID = 8683452581122892189L;//序列化的标志

   private static final int DEFAULT_CAPACITY = 10;//Default initial capacity.即默认初始化的ArrayList的大小

   private static final Object[] EMPTY_ELEMENTDATA = http://www.mamicode.com/{};//共享空数组实例用于空实例

   private transient Object[] elementData;//数组缓冲区存储数组列表的元素,存储元素的数组

  private int size;//数组元素的大小

  

4.ArrayList的构造方法

  初始化指定大小的列表,初始化大小为initialCapacity,如果参数小于0则会抛出参数非法异常,如果参数大于0,则创建指定大小的Object数组,使elementData元素指向数组

public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = http://www.mamicode.com/new Object[initialCapacity];>


初始化ArrayList里面的elementData,利用一个空的Object数组初始化EMPTY_ELEMENTDATA

public ArrayList() {
        super();
        this.elementData = http://www.mamicode.com/EMPTY_ELEMENTDATA;>


使用指定的集合初始化列表,列表的长度就是集合元素c的长度,及集合c的数据元素的个数

public ArrayList(Collection<? extends E> c) {
        elementData = http://www.mamicode.com/c.toArray();
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = http://www.mamicode.com/Arrays.copyOf(elementData, size, Object[].class);
    }


elementData = http://www.mamicode.com/Arrays.copyOf(elementData, size, Object[].class);//这一句是进行数组的复制



5.ArrayList常用的方法

//将此 ArrayList 实例的容量调整为列表的当前大小,去掉列表中多余的空间,
public void trimToSize() {
    modCount++;
    if (size < elementData.length) {//如果目前的元素个数小于elementData的空间个数,即有多余的空间浪费了没有使用
        elementData = http://www.mamicode.com/Arrays.copyOf(elementData, size);//进行数组的复制,去掉多余的空间>

//如果有必要的话,增加列表空间的大小,确保列表能够存放下元素
public void ensureCapacity(int minCapacity) {
	//最小的扩张列表的大小
    int minExpand = (elementData != EMPTY_ELEMENTDATA)//如果elementData不等于EMPTY_ELEMENTDATA
        // any size if real element table
        ? 0
        // larger than default for empty table. It's already supposed to be
        // at default size.
        : DEFAULT_CAPACITY;//默认的大小及定义的10
    //如果最小的空间长度大于最小规定的扩展长度则进行扩展
    if (minCapacity > minExpand) {
        ensureExplicitCapacity(minCapacity);
    }
}

进行列表的扩容

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 = http://www.mamicode.com/Arrays.copyOf(elementData, newCapacity);>

返回列表元素的长度

public int size() {
        return size;
    }


判断是否为空

public boolean isEmpty() {
        return size == 0;
    }



//从前到后依次查找元素在集合中第一次出现的下标,如果找到了则返回下标,没有则返回-1
public int indexOf(Object o) {
    if (o == null) {//如果元素为null
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)//如果列表中存在为null的元素,则返回下标
                return i;//返回下标
    } else {//如果元素o不为null
        for (int i = 0; i < size; i++)//进行顺序查找
            if (o.equals(elementData[i]))//进行判断,如果存在相等,则返回下标i
                return i;//返回下标
    }
    return -1;//没有查找到,则返回-1
}


//进行判断,元素o是否存在于列表中
public boolean contains(Object o) {
	//如果查找到了,则返回true,没有查找到则返回false
    return indexOf(o) >= 0;//返回结果
}



//从后向前依次查找元素在集合中第一次出现的下标,如果找到了则返回下标,没有则返回-1
public int lastIndexOf(Object o) {
    if (o == null) {//如果元素为null
        for (int i = size-1; i >= 0; i--)
            if (elementData[i]==null)//如果列表中存在为null的元素,则返回下标
                return i;//返回下标
    } else {
        for (int i = size-1; i >= 0; i--)//进行顺序查找
            if (o.equals(elementData[i]))//进行判断,如果存在相等,则返回下标i
                return i;//返回下标
    }
    return -1;//没有查找到,则返回-1
}



//把列表转换成数组进行返回
public Object[] toArray() {
    return Arrays.copyOf(elementData, size);//数组进行复制,返回复制后的数组
}


//返回集合中包含的数组a的所有元素
public <T> T[] toArray(T[] a) {
    if (a.length < size)//如果数组a长度小于列表的长度,则直接把列表前size个元素复制给a数组
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());//返回复制后的结果
    System.arraycopy(elementData, 0, a, 0, size);//如果数组a的长度大于列表的长度,则把列表从0到size的元素复制给a数组
    if (a.length > size)//如果a的长度大于size,则a数组有值的最后一个空的空间置位null
        a[size] = null;
    return a;//返回a数组
}


//得到指定位置的元素
public E get(int index) {
    rangeCheck(index);//进行参数的检查,看是否在可控的范围内

    return elementData(index);//返回指定下标的元素
}


//把更改指定位置的值
public E set(int index, E element) {
    rangeCheck(index);//进行参数的检查

    E oldValue = http://www.mamicode.com/elementData(index);//得到改变前指定位置的元素>

//在列表的末尾添加元素
public boolean add(E e) {
	//进行空间的检查,看空间是否够存入新的元素,不够的话进行分配新的空间
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;//把元素放到列表的最后,元素的个数size加1
    return true;//元素添加成功后,返回true
}


//在指定的位置插入元素
public void add(int index, E element) {
    rangeCheckForAdd(index);//检查参数index范围

    //确保空间足够添加元素
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //进行数组元素的复制操作,把index以后的所有元素往后移动一个位置
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;//在index位置插入元素element
    size++;//列表元素的个数加1
}


//删除指定位置的元素
public E remove(int index) {
    rangeCheck(index);//参数检查

    modCount++;
    E oldValue = http://www.mamicode.com/elementData(index);//得到删除前指定位置的元素>


//删除指定的元素o
public boolean remove(Object o) {
    if (o == null) {//如果元素o为空
        for (int index = 0; index < size; index++)//顺序查找是否存在为null的元素
            if (elementData[index] == null) {//如果为null
                fastRemove(index);//进行快速删除
                return true;//返回结果
            }
    } else {//如果元素o不为空
        for (int index = 0; index < size; index++)//进行查找
            if (o.equals(elementData[index])) {//如果找到了与元素o相等的元素
                fastRemove(index);进行快速删除
                return true;//返回结果true
            }
    }
    return false;//返回结果false
}



//私有的方法,进行快速的删除操作,删除指定的位置元素index
private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;//需要移动元素的长度
    if (numMoved > 0)//如果移动的长度数量大于0
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);//进行移动复制
    //元素数量减一,最后一个元素置为null
    elementData[--size] = null; // clear to let GC do its work
}



//清空列表中所有的元索
public void clear() {
    modCount++;

    // clear to let GC do its work
    for (int i = 0; i < size; i++)//进行循环,把所有的元素置位null
        elementData[i] = null;//把元素置位null

    size = 0;//列表的大小置位0
}




//把一个集合的元素添加到列表中
public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();//把集合转换成Object数组
    int numNew = a.length;//得到Object数组的大小
    //看是否需要开辟空间,需要则进行开辟新的空间
    ensureCapacityInternal(size + numNew);  // Increments modCount
    System.arraycopy(a, 0, elementData, size, numNew);//进行数组的复制
    size += numNew;//列表元素的长度变了
    return numNew != 0;//添加完成以后的返回值
}




//从指定的位置开始,把一个集合添加到列表中
public boolean addAll(int index, Collection<? extends E> c) {
    rangeCheckForAdd(index);//index下标检查

    Object[] a = c.toArray();//转换成数组
    int numNew = a.length;//得到长度
    //开辟空间
    ensureCapacityInternal(size + numNew);  // Increments modCount

    int numMoved = size - index;//得到需要移动的长度
    if (numMoved > 0)//如果移动的长度大于0
        System.arraycopy(elementData, index, elementData, index + numNew,
                         numMoved);//进行数组移动的复制

    System.arraycopy(a, 0, elementData, index, numNew);//数组的复制
    size += numNew;//列表元素长度增加
    return numNew != 0;//返回添加的结果
}


//删除列表中指定范围的元素
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;//置位null
    }
    size = newSize;//列表中新的元素的长度
}