Iterator
ArrayList的迭代器:
普通的Itr和ListItr,ListItr继承Itr,实现了更多的功能,ListItr继承Itr.Itr本身只能向后迭代。而ListItr既能 向后迭代,也能向前迭代。
Iterator对象称为迭代器,主要用于遍历Collection集合中的元素
Iterator仅用于遍历集合,不存储对象
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayList_class {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
Iterator<Integer> itr = list.iterator();
while (itr.hasNext()){
Integer next = itr.next();
System.out.println(next);
}
}
}
1. 扩容
ArrayList的扩容过程如下:
- 当要添加一个新元素到ArrayList时,首先检查当前元素数量是否达到了数组的容量上限。如果达到了容量上限,则需要进行扩容操作。
- 扩容操作会创建一个新的更大容量的数组,并将原数组中的元素复制到新数组中。
- 扩容通常会选择一个合适的增长策略,例如每次扩容增加当前容量的一半或固定增加一定数量的元素空间。
- 复制元素到新数组后,ArrayList会开始使用新数组作为其底层数组,并更新容量信息。
- 添加新元素到扩容后的ArrayList中。
扩容操作可能会导致一定的性能开销,因为需要重新分配内存并复制元素。因此,在预先知道ArrayList可能需要存储大量元素时,可以通过初始化ArrayList时设置一个较大的初始容量,来减少扩容操作的频率,提高性能。
需要注意的是,虽然ArrayList会自动进行扩容操作,但频繁进行大量元素的插入和删除操作仍可能导致性能下降,因为每次操作都需要移动大量元素。在这种情况下,考虑使用LinkedList或其他数据结构可能更合适。
private void grow(int minCapacity) {
// 获取当前数组的容量oldCapacity
int oldCapacity = elementData.length;
//创建一个新容量,是原来容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//将newCapacity设置为minCapacity,以确保扩容后的容量能够容纳最小需求
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//调用hugeCapacity
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// Arrays.copyOf方法将原数组elementData复制到一个新的数组中,并将新数组赋值给elementData,完成扩容操作
elementData = Arrays.copyOf(elementData, newCapacity);
}
//边界检查和处理
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
2. Iterator底层
- 调用ArrayList的iterator()方法:这个方法会返回一个实现了Iterator接口的迭代器对象。
public Iterator<E> iterator() {
return new Itr();
}
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
- 在迭代器对象中,会维护一个指针,指向当前元素的位置。
private class Itr implements Iterator<E> {
int cursor; // 迭代器要返回的下一个元素的索引。
int lastRet = -1; // 迭代器返回的最后一个元素的索引。
int expectedModCount = modCount;//这个变量用于跟踪ArrayList的预期修改次数,以便检测并发修改。(判断内外部操作数是否一致,如果不一致说明在迭代过程中元素数量发生了变化)
Itr() {}
//将cursor(光标)与列表的size进行比较,检查是否还有下一个元素。
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
//检测ArrayList是否发生了修改
checkForComodification();
int i = cursor;
//光标超出列表末尾,抛异常
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
//光标移动
cursor = i + 1;
//返回当前cursor索引处的元素,并更新lastRet以记录最后返回元素的索引
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;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
//列表中的元素数量
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
//获取 ArrayList 的元素数组 elementData
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
//将元素数组 elementData 中的元素传递给传入的 consumer 对象进行处理,并将迭代索引 i 自增。
consumer.accept((E) elementData[i++]);
}
// 更新迭代器的 cursor 为 i,表示迭代器的下一个元素位置
cursor = i;
//lastRet 为 i - 1,表示迭代器最后一个返回元素的索引
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
- 使用迭代器的hasNext()方法:这个方法检查指针指向的位置是否有下一个元素。如果有,返回true;如果没有,返回false。
public boolean hasNext() {
return cursor != size;
}
- 使用迭代器的next()方法:这个方法返回指针指向的当前元素,并且将指针移动到下一个位置。
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
//获取 ArrayList 的元素数组 elementData
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
//迭代器将移动到下一个位置
cursor = i + 1;
//即返回当前迭代位置的元素,并将 lastRet 更新为 i,表示当前迭代位置的索引
return (E) elementData[lastRet = i];
}
- 循环遍历:使用迭代器的hasNext()方法在每次循环迭代时检查是否还有下一个元素,如果有则调用next()方法取得该元素并进行相应的操作。
- 遍历结束:当迭代器指针移动到最后一个元素之后,再次调用hasNext()方法将返回false,循环结束。
迭代器实现了Iterator接口的方法,包括hasNext()和next()方法,通过这两个方法实现对ArrayList集合的遍历。 在使用迭代器遍历过程中,如果在迭代过程中对集合进行了结构性的修改(如添加或删除元素),迭代器会检测到并抛出ConcurrentModificationException异常,防止遍历过程中的并发修改错误。
使用迭代器遍历ArrayList集合时,在底层会创建迭代器对象并维护一个指针,通过调用hasNext()和next()方法实现对集合元素的遍历