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的元素要使用迭代器