JDK1.7源码笔记之ArrayList类

1. class 简介

  ArrayList是Java集合家族中最常用的容器,本质上是一个长度可变的array,它提供了一系列操作数组的方法,增加元素、删除元素、修改元素、根据索引取元素、迭代、扩容、取子列表、转换成数组等方法。使用ArrayList要注意尽量减少自动扩容的次数,以降低性能开销。

2. class内部原理及特点

  1. 不是线程安全的,没有Synchronized关键字。
  2. 允许向其中添加null。
  3. 内部是一个数组Object[] elementData,因为设计者设计java集合时还没有引进泛型概念。数组的优势在于快速检索,所以其按索引取值、修改和尾部添加等操作有优势,尽量不要进行插入和删除操作。
  4. 可以指定ArrayList的初始容量,默认为10,当内部数组已满,则当前总容量X1.5扩容,扩容时新建一个数组,将旧数组内容使用System.arraycopy复制到新数组。可以预估数据的数量,以减少频繁扩容带来的开销。.
  5. 其迭代器是快速失败的(java.util下的集合都是),在一个ArrayList的迭代器创建之后调用非迭代器中的方法对ArrayList的内部结构进行修改都会抛出ConcurrentModificationException。

3. class源码细节分析

  对数组进行增删改查的操作在学习数据结构的时候已经非常熟悉了,没必要浪费时间,这里先看其它容易被忽视的核心方法。  

ensureCapacity, ensureCapacityInternal和grow
/* 负数容量无视 */
public void ensureCapacity(int minCapacity) {
if (minCapacity > 0)
        ensureCapacityInternal(minCapacity);
}
/* ArrayList的内部数组只能扩大不能缩小 */
private void ensureCapacityInternal(int minCapacity) {
    modCount++;//记录修改的次数,用于在迭代器迭代过程中检测是否有其它线程对容器进行了修改。
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
/* 1.5倍扩容,如果还不够则直接等于所需容量 */
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);//X1.5倍
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)//超过最大限制
        newCapacity = hugeCapacity(minCapacity);//则等于最大值
    //新创建一个数组,把内容copy到新数组中
    elementData = Arrays.copyOf(elementData, newCapacity);
}
batchRemove, removeAll和retainAll
public boolean removeAll(Collection<?> c) {
    return batchRemove(c, false);
}
public boolean retainAll(Collection<?> c) {
    return batchRemove(c, true);
}
/* 移除和保留是相反的操作,complement表示是否进行相反操作 */
private boolean batchRemove(Collection<?> c, boolean complement){
    final Object[] elementData = this.elementData;
    int r = 0, w = 0;
    boolean modified = false;
    try {
        for (; r < size; r++)//包含这个元素则选择覆盖或跳过
            if (c.contains(elementData[r]) == complement)
                elementData[w++] = elementData[r];
    } finally {
       // Preserve behavioral compatibility with AbstractCollection,
    // even if c.contains() throws.
    if (r != size) {
        System.arraycopy(elementData, r,
                         elementData, w,
                         size - r);
        w += size - r;
    }
    if (w != size) {
        for (int i = w; i < size; i++)
            elementData[i] = null;
        modCount += size - w;
        size = w;
        modified = true;
    }
    return modified;
}
subList
/* 
返回ArrayList某个部分的视图(一个子列表),其拥有ArrayList所有的方法,对SubList进行任何操作都会反映到本体ArrayList中,对其产生相同的影响 
*/
public List<E> subList(int fromIndex, int toIndex) {
    subListRangeCheck(fromIndex, toIndex, size);
    return new SubList(this, 0, fromIndex, toIndex);
}
iterator
public Iterator<E> iterator() {
    return new Itr();
}
private class Itr implements Iterator<E> {
    int cursor;       //初始为0,指向下一个元素
    int lastRet = -1; //指向上一次的元素,没有则为-1
    int expectedModCount = modCount;//用于在迭代过程中和容器的modeCount进行比较,检测是否有别的线程修改了容器。
    public boolean hasNext() {//是否还有元素
        return cursor != size;
    }
    @SuppressWarnings("unchecked")
    public E next() {//下一个元素
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }
    public void remove() {//移除上一次的元素,所以如果要用迭代器删除list的第一个元素,必须先调用一次next()
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();
        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}
//实现了List接口的集合容器还有一个listIterator方法,其返回的迭代器可以前后迭代。

ArrayList以及其它非Map集合的终极父类Collection实现了Iterable接口,可以在foreach语句中遍历集合for(Object o : collection){},实际上是使用了迭代器。

//Implementing this interface allows an object to be the target of the "foreach" statement.
//@param <T> the type of elements returned by the iterator
 *
 * @since 1.5
 */
public interface Iterable<T> {

    /**
     * Returns an iterator over a set of elements of type T.
     *
     * @return an Iterator.
     */
    Iterator<T> iterator();
}

4. 总结  

  ArrayList是最常用的java集合,由于在集合被加入JDK之前还没有泛型,在源码中经常可以看到Object类型。使用ArrayList要尽量减少其扩容的次数,尽量不要对其进行插入和删除的操作,在需要的时候手动扩容。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值