ArrayList源码详解

时间:2019-02-19
本文章向大家介绍ArrayList源码详解,主要包括ArrayList源码详解使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

ArrayList

1特点
适合做查找;不适合做删除和插入,这样会复制,移动元素;
查找O(1),删除和插入为O(n)

默认构造器

无参数初始空数组,new时,数组大小仍然为空,一旦添加就扩容变成10;


private static final Object[] EMPTY_ELEMENTDATA = {};
<!--与上面都是空数组,但是带大小的构造器初始化时,会使让该数组变成该大小,之后不再改变。最后通过比较element的大小来知道数组变大了多少。-->
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
<!--真正被操控的数组-->
transient Object[] elementData;

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

指定大小有参数构造

public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

将集合作为参数传入构造器

public ArrayList(Collection<? extends E> c) {
<!--element最后的类型可能不是c的类型数组而是c的子类,由于java运行时多态的原因,此时再element添加一个c类型的元素就会报错java.lang.ArrayStoreException-->
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        <!--为了避免上述原因,需要重新转化-->
        if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

末尾直接添加

public boolean add(E e) {
    //确保容量够用
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

rivate void ensureCapacityInternal(int minCapacity) {
//第一添加时,初始化数组大小,如果初始化大小《10 (默认大小),直接使用默认大小。
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    
    ensureExplicitCapacity(minCapacity);
}
<!--确保size不会因为二进制加法溢出变成负数-->
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // 添加一个元素后使得,元素个数超过了数组的大小就扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
<!--《真正的扩容》-->
private void grow(int minCapacity) {
    // overflow-conscious code
    <!--旧数组长度-->
    int oldCapacity = elementData.length;
    <!--新数组长度等于旧数组长度的1.5倍-->
    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 = Arrays.copyOf(elementData, newCapacity);
}

指定位置添加

public void add(int index, E element) {
    rangeCheckForAdd(index);
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1, size - index);
    elementData[index] = element;
    size++;
}

将一个集合全部添加到一个list里面

public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
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);

    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount

    int numMoved = size - index;
    if (numMoved > 0)
        System.arraycopy(elementData, index, elementData, index + numNew, numMoved);

    System.arraycopy(a, 0, elementData, index, numNew);
    size += numNew;
    return numNew != 0;
}

删除

删除指定索引,数组整体前移。

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;
}

删除指定对象

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;
}

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
}

查找

public E get(int index) {
    rangeCheck(index);
    return elementData(index);
}

迭代

边遍历边删除元素时,最好使用迭代器模式,不会出问题
,使用for循环会出现ConcurrentModificationException;


 ArrayList<Integer> integers1 = new ArrayList<>();
        Iterator<Integer> iterator = integers.iterator();
        while (iterator.hasNext()) {
            if (iterator.next() == 1) {
               iterator.remove();
            }
}