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的扩容过程如下:

  1. 当要添加一个新元素到ArrayList时,首先检查当前元素数量是否达到了数组的容量上限。如果达到了容量上限,则需要进行扩容操作。
  2. 扩容操作会创建一个新的更大容量的数组,并将原数组中的元素复制到新数组中。
  3. 扩容通常会选择一个合适的增长策略,例如每次扩容增加当前容量的一半或固定增加一定数量的元素空间。
  4. 复制元素到新数组后,ArrayList会开始使用新数组作为其底层数组,并更新容量信息。
  5. 添加新元素到扩容后的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底层

  1. 调用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());
    }
}
  1. 在迭代器对象中,会维护一个指针,指向当前元素的位置。
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();
        }
    }
  1. 使用迭代器的hasNext()方法:这个方法检查指针指向的位置是否有下一个元素。如果有,返回true;如果没有,返回false。
public boolean hasNext() {
            return cursor != size;
        }
  1. 使用迭代器的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];
        }
  1. 循环遍历:使用迭代器的hasNext()方法在每次循环迭代时检查是否还有下一个元素,如果有则调用next()方法取得该元素并进行相应的操作。
  2. 遍历结束:当迭代器指针移动到最后一个元素之后,再次调用hasNext()方法将返回false,循环结束。

迭代器实现了Iterator接口的方法,包括hasNext()和next()方法,通过这两个方法实现对ArrayList集合的遍历。 在使用迭代器遍历过程中,如果在迭代过程中对集合进行了结构性的修改(如添加或删除元素),迭代器会检测到并抛出ConcurrentModificationException异常,防止遍历过程中的并发修改错误。

使用迭代器遍历ArrayList集合时,在底层会创建迭代器对象并维护一个指针,通过调用hasNext()和next()方法实现对集合元素的遍历