ArrayList 详解

remove的核心处理 & add在扩容或其余进行数组移动操做( eg. addAll、add(index, obj)), 时都涉及数组元素的复制移动System.arraycopy调用native方式。java

remove

从 index+1 至 end 的元素前移数组

add

在初始化时若没指定容量则构建的是空数组,在第一次add时,扩容至DEFAULT_CAPACITY= 10.  this

默认下的扩容策略是: 原容量/2 (newCapacity = oldCapacity + (oldCapacity >> 1))spa

private void grow(int minCapacity) { 
        // overflow-conscious code
        int oldCapacity = elementData.length;
        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);
    }

在扩容时,须要经过Arrays.copyOf来复制数组元素(实现也是System.arraycopy)3d

重要成员

  • Object[] elementData:经过内部维护数组来存储数据。 在add时会断定是否须要须要扩容(最大限制是Integer.MAX_VALUE)
  • int size: 实际维持的元素个数 数。 add时加一, remove时减一。
    与elementData.length不是一个意思。在writeObject方法中能佐证)
  • int modCount: 继承自AbstractList, 用来肯定arrayList的结构变动(新增、扩容、删除、排序、清空)次数, 只有++; 由迭代器(Iterator)和列表迭代器(ListIterator)使用,当进行next()、remove()、previous()、set()、add()等操做时,若是modCount的值意外改变,就会抛出ConcurrentModificationException异常。
public static void main(String[] args) throws Exception {
		ArrayList<String> list = new ArrayList<String>(1);

		Field file = ArrayList.class.getDeclaredField("elementData");
		file.setAccessible(true);
		Object[] object = (Object[]) file.get(list);
		System.out.println("初始size: " + list.size());
		System.out.println("初始数组容量:" + object.length);

		list.add("1");
		Object[] object1 = (Object[]) file.get(list);
		System.out.println("添加第1个元素后的size:" + list.size());
		System.out.println("添加第1个元素后的数组容量:" + object1.length);
		
	}

初始化指定容量执行结果:
code

初始化不指定容量执行结果:
blog

ConcurrentModificationException

  • 只要实现了Iterator接口的类,均可以使用for-Each循环来遍历!
  • 集合循环遍历时所使用的迭代器Iterator有一个要求:在迭代的过程当中,除了使用迭代器(如:Iterator.remove()方法)对集合增删元素外,是不容许直接对集合进行增删操做。不然将会抛出 ConcurrentModificationException异常。因此,因为集合的for-Each循环本质上使用的仍是Iterator来迭代,所以也要注意这个陷阱。

在for循环中直接remove时抛出异常
排序

普通的for循环方式删除元素时是经过System.arraycopy调用native的方式进行数组边界内的复制, size一直会在变化,结果没法控制(没法清空数据或下标越界异常)继承

for-Each循环是经过扩展Iterable接口的iterator()方法返回在ArrayList内部对于Iterator接口的实现类Itr来进行处理。接口

类中一个重要元素expectedModCount初始值等于modCount。

在next()执行阶段会调用checkForComodification() 来断定modCount与expectedModCount是否一致, 不然抛出异常。
而在Iterator.remove方法会从新设置expectedModCount值, 因此当调用Iterator.next等方法时checkForComodification不会报错。

相关文章
相关标签/搜索