ArrayList源码分析(基于JDK1.8)

首先了解ArrayList集合类常用的构造方法以及常用的成员方法:
常用的构造方法有:

ArrayList<E>();     //默认构造器
ArrayList<E>(Collection <? extends E> c);      //将容器C作为构造参数
ArrayList(int initialCapacity);    //以初始容量作为构造参数

常用的成员方法有:

//添加元素的方法
 boolean add(E e);  
 boolean addAll(Collection <? extends E> c);

//获取元素的方法 
 E get(int index);
 boolean isEmpty();
 int size();
 Iterator<E> iterator();


//删除元素方法 
E remove(int index);

下面将通过阅读源码对上述方法进行逐个分析:

1. 首先看一下ArrayList类的定义

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

由上述代码可见, ArrayList类实现了List、RandomAccess、Cloneable、Serializable接口,同时扩展了AbstractList类。
ArrayList中定义成员变量如下:

//缺省的初始化容量
private static final int DEFAULT_CAPACITY = 10;

//Shared empty array instance used for empty instances.
//共享的空数组实例,用于新建ArrayList空实例,static final修饰
private static final Object[] EMPTY_ELEMENTDATA = {};

//共享的空数组实例,用于新建默认大小的空ArrayList实例。采用static final修饰。
//区别与上面的EMPTY_ELEMENTDATA是为了当插入第一个元素时用该扩展为默认容量DEFAULT_CAPACITY。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

//数组用于缓冲保存在ArrayList中的元素。
//数组的长度就是ArrayList的容量。
transient Object[] elementData; 

//ArrayList所包含元素的个数
private int size;

//elementData数组所能分配的最大数组长度
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

2. 分析ArrayList构造方法

2.1 ArrayList()构造方法
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

将默认空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA复制给elementData.

2.2ArrayList<E>(Collection <? extends E> c)构造方法
public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();   //将容器中的元素转变为数组
        if ((size = elementData.length) != 0) {   //如果容器C中的元素个数不为0
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            //如果容器C中元素个数为0,则将elementData赋值为空数组EMPTY_ELEMENTDATA
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
2.3 ArrayList(int initialCapacity) 构造方法
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {   //如果用户指定的初始化容量大于0
            this.elementData = new Object[initialCapacity];   //则将elementData数组新建长度为initialCapacity
        } else if (initialCapacity == 0) {  如果用户指定的初始化容量等于0
            this.elementData = EMPTY_ELEMENTDATA;   //令elementData数组赋值为空数组
        } else {  //如果用户指定的初始化容量小于0, 则会抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

3. 元素的添加

3.1 add(E e)方法
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  调用了ensureCapacity方法,是否需要进行扩增
        elementData[size++] = e;    //插入元素到elementData中,并将size加1,记录ArrayList中元素个数
        return true;   //返回成功
    }

private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {      //如果elementData数组为默认空数组
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);   //取默认容量和输入参数中较大者
        }
        ensureExplicitCapacity(minCapacity);   //是否扩增的必要
    }

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;    //modCount++修改次数自增

    if (minCapacity - elementData.length > 0)     //如果增加的元素已经超过了elementData数组的长度
        grow(minCapacity);    //调用grow函数进行扩增
}

private void grow(int minCapacity) {
        int oldCapacity = elementData.length;    //获取elementData原长度
        int newCapacity = oldCapacity + (oldCapacity >> 1);   //新容量扩增为原来的1.5倍
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;    //如果仍然比所需的最小容量minCapacity小,则新长度为minCapacity,主要发生在新建数组数组为空时插入第一个元素
        if (newCapacity - MAX_ARRAY_SIZE > 0)  //如果新容量大于最大容量
            newCapacity = hugeCapacity(minCapacity);   //根据原来所需的最小容量进行扩增,而所需容量的最小值通常跟size差不多大
        elementData = Arrays.copyOf(elementData, newCapacity);   //扩增后复制原数组中元素
 }

private static int hugeCapacity(int minCapacity) {  //当需要新容量大于最大容量时
        if (minCapacity < 0)   //如果minCapacity<0,说明长度由最大溢出为负数
            throw new OutOfMemoryError();   
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :   //返回Integer的最大
            MAX_ARRAY_SIZE;    //否则返回数组最大容量限制
}
3.2 addAll(Collection <? extends E> c)方法
public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;   //获取将要添加的容器中元素个数
        ensureCapacityInternal(size + numNew);  // 查看当前ArrayList元素个数+新增元素个数是否大于elementData数组长度,从而判断是否需要进行扩增
        System.arraycopy(a, 0, elementData, size, numNew);        //新增元素添加到elementData数组size位置后
        size += numNew;  //改变ArrayList中元素的总数
        return numNew != 0;  //如果c为空,返回false
}

4. 元素的获取

4.1 get(int index)方法
public E get(int index) {
        rangeCheck(index);  //判断访问位置是否产生越界行为
        return elementData(index);  //返回数组相应位置的元素
    }

private void rangeCheck(int index) {
        if (index >= size)  //判断元素位置是否大于等于size,如果大于等于,则出现了访问越界,抛出异常
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
4.2 isEmpty()方法
public boolean isEmpty() {
        return size == 0;   //通过判断size==0
    }
4.3 size()方法
public int size() {
        return size;
    }
4.4 iterator()方法
public Iterator<E> iterator() {
        return new Itr();  //返回ArrayList中的内部类Itr
    }

//分析内部类Itr中的主要方法
private class Itr implements Iterator<E> {
        int cursor;       // 下一个返回元素所在下标
        int lastRet = -1; // 上一个返回元素的下标
        int expectedModCount = modCount;  //记录修改次数

        public boolean hasNext() {
            return cursor != size;  //当前游标没有等于size
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();  //检查是否其他线程对ArrayList进行了修改
            int i = cursor;  //赋值为即将返回的元素所在下标
            if (i >= size)  //大于size则抛出异常
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;  //令局部数组引用指向外部的elementData引用
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;    //令游标指向下一个元素
            return (E) elementData[lastRet = i];  //返回i指向的元素,并将i复制给lastSet记录上一个元素的下标。
          }

        final void checkForComodification() {  //检查是否有其他线程同时修改ArrayList
            if (modCount != expectedModCount)  //如果有其他线程对ArrayList进行了修改,则抛出异常,快速失败
                throw new ConcurrentModificationException();
        }

5. 元素的删除

5.1 remove(int index)方法
public E remove(int index) {
        rangeCheck(index);  //同样需要对index进行越界访问检查
        modCount++;  //将修改次数加1
        E oldValue = elementData(index);  //获取index位置处的元素

        int numMoved = size - index - 1;  //需要将index之后的元素往前移,numMoved保存需要往前移动的元素个数
        if (numMoved > 0)   //如果需要进行移动的个数大于0
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);   //复制移动
        elementData[--size] = null; //将size减1,前移之后需要同时将原来数组最后一个元素位置size-1置为Null,方便GC回收。

        return oldValue;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值