ArrayList源码分析

简介

ArrayList提供了List ADT的一种可增长数组的实现,底层基于数组实现,对get/set的调用花费常数时间,但插入/删除项则代价昂贵。

构造函数

这里面涉及到三个数组,EMPTY_ELEMENTDATADEFAULTCAPACITY_EMPTY_ELEMENTDATAelementData,其中前两个数组主要用于在初始化以作区分,详见构造函数的区别。其中elementData是数据实际存储的数组,它使用transient关键字创建。
在这儿有三种构造函数:

  • MyArrayList(int initialCapacity)
    若传参为0,elementData会指向EMPTY_ELEMENTDATA(未指定长度),若>0则创建数组new Object[initialCapacity],<0则抛出异常。
  • MyArrayList()
    采用这种构造函数创建ArrayList,elementData会指向DEFAULTCAPACITY_EMPTY_ELEMENTDATA(未指定长度)
  • MyArrayList(Collection<? extends E> c)
    以数组的形式建立

采用MyArrayList(int initialCapacity)MyArrayList()构造的数组在调用add方法时,处理逻辑会不一样,依次调用ensureCapacityInternal()(它调用后两者,故不做介绍),calculateCapacity(),ensureExplicitCapacity()三个函数

  • calculateCapacity():若是以 MyArrayList()构造函数创建的ArrayList,首次赋值按照Math.max(DEFAULT_CAPACITY, minCapacity)的方式增加数组容量,也就是说<DEFAULT_CAPACITY时,取DEFAULT_CAPACITY;
  • ensureExplicitCapacity:针对MyArrayList()MyArrayList(int initialCapacity)当容量不够时,均按照1.5倍old容量进行扩容。
    流程图如下:
    add()方法的流程图
    当数组length快溢出时,执行以下的逻辑
/**
 * 有些VM会用8的长度来存储数组_length字段,记录数组长度,只需要去读_length字段就可以了
 * 如果值比这个还大,就会溢出(当一个整数一直++,超出最大值后会变成负值)
 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}
删除
  • 单个删除
//按位置删除
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;
}
//根据index返回elementData元素
@SuppressWarnings("unchecked")
E elementData(int index) {
    return (E) elementData[index];
}

//按对象删除
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(Object o)调用前已经能确保该元素位于elementData[]中,故:
//1.无需判断index合法性;
//2.无需返回删除的元素(删除的元素调用方是知晓的)
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
}

//按数组删除,也就是如果elementData[]里存在c的元素,则删除
public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }

//按数组保留,也就是如果elementData[]里存在c的元素,则保留
public boolean retainAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, true);
}

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.
        // 避免出现Exception(什么时候会出Exception???)的时候好将原数组后续的元素保留下来
        if (r != size) {
            System.arraycopy(elementData, r,
                             elementData, w,
                             size - r);
            w += size - r;
        }
        //由于elementData中元素被删除了一部分,因此后续的元素需要补null,等待GC处理
        if (w != size) {
            // clear to let GC do its work
            for (int i = w; i < size; i++)
                elementData[i] = null;
            modCount += size - w;
            size = w;
            modified = true;
        }
    }
    return modified;
}
修改

直接替换元素,比较高效的操作

public E set(int index, E element) {
    rangeCheck(index);

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

直接根据index获取元素,相比与LinkedList而言非常高效

public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}
@SuppressWarnings("unchecked")
E elementData(int index) {
    return (E) elementData[index];
}
清空

跟删除罗辑一直,GC会自动完成优化

public void clear() {
    modCount++;

    // clear to let GC do its work
    for (int i = 0; i < size; i++)
        elementData[i] = null;

    size = 0;
}
包含
public boolean contains(Object o) {
    return indexOf(o) >= 0;
}
public int indexOf(Object o) {
	
    if (o == null) {
        for (int i = 0; i < size; i++)
        	//对象在没有被分配空间时是不能调用任何方法的
        	//故此处不能用.equal(..)方法,否则会报java.lang.NullPointerException空指针异常
            if (elementData[i]==null)	
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}
判空
public boolean isEmpty() {
    return size == 0;
}
迭代器
public Iterator<E> iterator() {
    return new Itr();
}

private class Itr implements Iterator<E> {
    int cursor;       // index of next element to return
    int lastRet = -1; // index of last element returned; -1 if no such
    //只要实例化了Itr对象,那么expectedModCount就会保留当时的modCount,如果非此Itr对象对elementData
    //进行了修改,那么modCount会改变,这样expectedModCount != modCount抛异常
    int expectedModCount = modCount;

    Itr() {}

    public boolean hasNext() {
        return cursor != size;
    }

    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();	
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        //ArrayList.this.remove()指调用外部类ArrayList的remove()方法
        Object[] elementData = ArrayList.this.elementData;
        //再次判断是否越界,害怕我们在这里的操作时,有异步线程修改了List
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }

    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }
	//此方法的解释见下文
    @Override
    @SuppressWarnings("unchecked")
    public void forEachRemaining(Consumer<? super E> consumer) {
        Objects.requireNonNull(consumer);
        final int size = ArrayList.this.size;
        int i = cursor;
        if (i >= size) {
            return;
        }
        final Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length) {
            throw new ConcurrentModificationException();
        }
        while (i != size && modCount == expectedModCount) {
            consumer.accept((E) elementData[i++]);
        }
        // update once at end of iteration to reduce heap write traffic
        cursor = i;
        lastRet = i - 1;
        checkForComodification();
    }

    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

有两个遍历元素的方法,位于Iterator中的forEachRemaining(Consumer<? super E> consumer),以及集合本身的forEach(Consumer<? super E> consumer),代码如下:

/*
* 他们均用于函数式编程中,详见Java函数式编程相关知识点
* 区别如下:
* forEachRemaining本质是while(iterator.hasNext()){iterator.next()}操作
* forEach本质是 for (Type e : collection) {...}操作
* 也就是说针对同一个iterator对象,forEachRemaining只能使用一次,第二次使用由于iterator.hasNext()为false,
* 故不会执行;而forEach可以执行多次
*/
public void forEachRemaining(Consumer<? super E> consumer) {
 Objects.requireNonNull(consumer);
    final int size = ArrayList.this.size;
    int i = cursor;
    if (i >= size) {
        return;
    }
    final Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length) {
        throw new ConcurrentModificationException();
    }
    while (i != size && modCount == expectedModCount) {
        consumer.accept((E) elementData[i++]);
    }
    // update once at end of iteration to reduce heap write traffic
    cursor = i;
    lastRet = i - 1;
    checkForComodification();
}

@Override
public void forEach(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    final int expectedModCount = modCount;
    @SuppressWarnings("unchecked")
    final E[] elementData = (E[]) this.elementData;
    final int size = this.size;
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        action.accept(elementData[i]);
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

举例如下:

List<String> stringList = new ArrayList<>();
stringList.add("a"); stringList.add("b"); stringList.add("c");
Consumer<String> consumer = System.out::println;
Iterator<String> iterator = stringList.iterator();
iterator.forEachRemaining(consumer);
iterator.forEachRemaining(consumer);	//第二次不会有输出
stringList.forEach(consumer);
stringList.forEach(consumer);	//第二次依然有输出

注意:还有一个遍历的对象ListItr,它是Itr的加强版,拥有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历等。

其它代码
  • 收缩,减少ArrayList的存储空间占用
public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}
  • 返回最后一个匹配元素的位置
    它是从后往前查找的,返回找到的第1个
public int lastIndexOf(Object o) {
    if (o == null) {
        for (int i = size-1; i >= 0; i--)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = size-1; i >= 0; i--)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}
  • 返回视图SubList
public List<E> subList(int fromIndex, int toIndex) {
	...
}

List的subList方法并没有创建一个新的List,而是使用了原List的视图,这个视图使用内部类SubList表示。修改其中一个,变更会反应到另一个上面:

  1. 对父(sourceList)子(subList)List做的非结构性修改(non-structural changes),都会影响到彼此。
  2. 对子List做结构性修改,操作同样会反映到父List上。
  3. 对父List做结构性修改,会抛出异常ConcurrentModificationException。
  • 分割
    分割后方便并行处理,
@Override
public Spliterator<E> spliterator() {
    return new ArrayListSpliterator<>(this, 0, -1, 0);
}

/** Index-based split-by-two, lazily initialized Spliterator */
static final class ArrayListSpliterator<E> implements Spliterator<E> {
...
}
  • 通过lambda表达式实现元素的删除
public boolean removeIf(Predicate<? super E> filter) {
	...
}
  • 通过lambda表达式实现元素的替换
    // 在所有元素末尾增加"aaa"字符
    stringList.replaceAll(x -> x + “aaa”);
public void replaceAll(UnaryOperator<E> operator) {
	...
}

在java 1.8中,函数编程的接口如下:PredicateConsumerFunctionSupplierUnaryOperator

  • 自定义sort规则实现排序
public void sort(Comparator<? super E> c) {
	...
}

支持重写Compare方法以自定义的规则实现排序。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值