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

ArrayList源码解析

add操作:
private transient Object[] elementData;
private static final int DEFAULT_CAPACITY = 10;
public ArrayList() {
    super();
    this.elementData =http://www.mamicode.com/ EMPTY_ELEMENTDATA;
}
public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
        this.elementData = http://www.mamicode.com/new Object[initialCapacity];
}

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // 添加之前检查数组容量,size+1表示接下来要有的容量
    elementData[size++] = e;//size初始默认值是0,每添加一个元素自增1,故size表示实际的数组长度
    return true;
}

private void ensureCapacityInternal(int minCapacity) {
    if (elementData =http://www.mamicode.com/= EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//如果elementData 为空集合,即则将传入的minCapacity和默认值10比较,选出较大的
    }
    ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    if (minCapacity - elementData.length > 0) //新建对象时如果指定大小则elementData.length为指定的大小,否则elementData.length=0;此处minCapacity 表示需要的数组长度,elementData.length表示扩容后的数组长度,如果是的数组长度
        grow(minCapacity);//扩容方法
}

private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);//>> : 右移运算符,num >> 1,相当于num除以2,此处扩容按照原容量大小的一般扩容
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);//将原有元素拷贝到扩容后的新数组中
}
总结:elementData 是ArrayList的中间数组,是实际数据的存放数组,size是数组实际的长度,elementData.length都是大于或者等于size的。
声明ArrayList数组时如果指定长度后向数组中添加元素,如果长度超出了ArrayList中间数组的长度(elementData.length)则会增加数组容量,增加原长度的一半容量
如果声明ArrayList数组时没有指定长度,则默认是空数组,在添加元素的时候,判断如果当前集合(中间数组)为空,则将默认长度10赋给数组,即添加第一个元素后的数组容量实际是10

 

删除(remove)操作:
 
remove(int 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数组 index+1位置上及后面的元素都复制到elementData中,从index位置接收复制元素,接收numMoved个元素
        elementData[--size] = null; // clear to let GC do its work 即将最后一个元素置null回收
        return oldValue;//返回被移除的元素
    }
总结:删除指定位置上的元素是将该数组中该位置以后的元素都往前移动一位,最后一位置null被回收
 
remove(Object o)删除此列表中首次出现的指定元素
public boolean remove(Object o) {
        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;
    }
//此方法和remove类似
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
    }

总结:移除时先判断是否是null,如果是要单独操作,因为null没有equals方法,通过逐个比较元素来判断要溢出的元素的位置,再通过类似于remove的方法移除元素

 
修改/设置(set)操作
set(int index, E element)用指定的元素替代此列表中指定位置上的元素。
public E set(int index, E element) {
        rangeCheck(index);
        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }
总结:直接将指定位置上的元素赋给要赋的值
 
查询/获取(get)操作:
public E get(int index) {
        rangeCheck(index);
        return elementData(index);
    }
总结:直接返回指定位置上的数组元素
 
 

ArrayList源码解析