/**
*Itr 实现了Iterator接口,是AbstractList中的一个内部类。
*/
private class Itr implements Iterator<E> {
//当前迭代器指向的数组中元素的下一个元素的位置
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;
//每次调用hasNext方法时,判断当前指向的数组中的位置和数组大小是否相等,若不等则返回true(说明还有值),若相等则返回false(说明已经迭代到了数组的末尾了,没有元素了)
public boolean hasNext() {
return cursor != size();
}
//调用next方法是,先调用checkForComodification()方法,判断是否有其他线程对集合大小做出了有影响的动作;
//然后调用get方法获取相应位置的元素,若获取不到,则抛出IndexOutOfBoundsException异常,在捕获到该异常后,调用checkForComodification()方法,
//检测modcount若== expectedModCount(没有其他线程对集合大小做出了有影响的操作),则抛出NoSuchElementException,若modcount != expectedModCount,则抛出ConcurrentModificationException
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
//若modCount和期望的expectedModCount不相等,说明在迭代过程中,有其他的线程对集合大小产生了影响的动作(新增、删除),此时抛出异常ConcurrentModificationException
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
我们在看一个方法trimToSize
/**
*将elementData数组的容量 缩小为该集合实际包含的元素数量
*/
public void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (size < oldCapacity) {
elementData = Arrays.copyOf(elementData, size);
}
}
使用ArrayList的注意事项:
1.ArrayList是基于数组的方式实现的,可以通过下标索引直接查找到指定位置的元素,因此查找效率高,但每次插入或删除元素,就要大量地移动元素,插入删除元素的效率低。
2.ArrayList在插入元素时,可能会进行数组的扩容,但是在删除元素时却不会减小数组的容量,如果希望减小数组的容量,可使用trimToSize方法,在查找元素要遍历数组时,对非null元素使用equals方法,对null元素使用==。
3.扩充容量的方法ensureCapacity。ArrayList在每次增加元素(可能是1个,也可能是一组)时,都要调用该方法来确保足够的容量。当 容量不足以容纳当前的元素个数时,就设置新的容量为旧的容量的1.5倍加1,如果设置后的新容量还不够,则直接新容量设置为传入的参数(也就是所需的容 量),而后用Arrays.copyof()方法将元素拷贝到新的数组。从中可以看出,当容量不够时,每次增加元素,都要将原来的元 素拷贝到一个新的数组中,非常之耗时,也因此建议在事先能确定元素数量的情况下,才使用ArrayList,否则建议使用LinkedList
4.ArrayList不是线程安全的。