arrays中copyof_为什么不要在for中删除ArrayList的元素

fc4d0dc54748792ba623dec9ac213de5.png

ArrayList的作用

Java中比较常用的可自动扩容的数组,它的优势是查询性能高,劣势是按顺序增删性能差

数据结构

数组

主要的类属性

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//保持元素的数组transient Object[] elementData;//数组中已有元素的个数private int size;//这个是父类中的属性,主要是记录修改次数protected transient int modCount = 0;

构造函数

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() {    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}

添加元素

public boolean add(E e) {    ensureCapacityInternal(size + 1);  // Increments modCount!!    elementData[size++] = e;    return true;}private void ensureCapacityInternal(int minCapacity) {    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//数组为空的话则默认初始容量为10    }    ensureExplicitCapacity(minCapacity);}private void ensureExplicitCapacity(int minCapacity) {    modCount++;    if (minCapacity - elementData.length > 0)        grow(minCapacity);}private void grow(int minCapacity) {    int oldCapacity = elementData.length;    int newCapacity = oldCapacity + (oldCapacity >> 1);//新数组的容量为原数组的1.5倍    if (newCapacity - minCapacity < 0)        newCapacity = minCapacity;    if (newCapacity - MAX_ARRAY_SIZE > 0)        newCapacity = hugeCapacity(minCapacity);    elementData = Arrays.copyOf(elementData, newCapacity); //创建一个新的数组,并将原来的元素拷贝到新数组,然后赋值给elementData}

每次添加元素时都会对modCount执行递增操作,并且会检查是否需要扩容,需要扩容的话扩容后再向数组中添加元素

删除元素

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++; //这里比较重要,删除元素modCount也会自增    int numMoved = size - index - 1;    if (numMoved > 0)        System.arraycopy(elementData, index+1, elementData, index,                         numMoved);//将元素右边的所有元素往左移一位    elementData[--size] = null; //将数组最后一个元素情况,size减1}

为什么不要在for中删除ArrayList的元素?

在老版本的for(int i = 0;i

找到ArrayList类的iterator()方法

public Iterator iterator() {    return new Itr();}

使用自己的Itr内部类,并且实现了Iterator接口,具体实现如下:

private class Itr implements Iterator {    int cursor;       // index of next element to return    int lastRet = -1; // index of last element returned; -1 if no such    int expectedModCount = modCount;    public boolean hasNext() {        return cursor != size;    }    @SuppressWarnings("unchecked")    public E next() {        checkForComodification();//modCount != expectedModCount抛出ConcurrentModificationException        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() {        if (lastRet < 0)            throw new IllegalStateException();        checkForComodification();        try {            ArrayList.this.remove(lastRet);            cursor = lastRet;            lastRet = -1;            expectedModCount = modCount; //将新的modCount值赋值给expectedModCount         } catch (IndexOutOfBoundsException ex) {            throw new ConcurrentModificationException();        }    }    final void checkForComodification() {        if (modCount != expectedModCount)            throw new ConcurrentModificationException();    }    ...}

迭代器的本质是先调用hasNext()方法判断存不存在下一个元素,然后再使用next()方法取下一个元素。

在for(String s: list)中调用list的remove()方法时变量modCount会自增,然后使用next()方法取下一个元素时,会判断迭代器的expectedModCount是否等于modCount,而expectedModCount是在初始迭代器时赋值的,初始值为modCount,在调list的remove()方法时modCount已经加1,所以在判断时expectedModCount!=modCount会抛出并发修改异常。

使用迭代器的remove()会将新的modCount赋值给expectedModCount,这也是为什么删除list的元素要使用迭代器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值