什么是迭代器
    维基百科解释:迭代器(iterator)有时又称光标(cursor)是程序设计的软件设计模式可在容器对象(container,例如链表或数组)上遍访的接口设计人员无需关心容器对象的内存分配的实现细节

    我们解释一下上面这段话:
      讲到迭代器,就离不开容器,也是是Java中经常讲到的集合(Java集合框架的集合类,我们有时候称之为容器)。容器的种类有很多种,比如ArrayList、LinkedList、HashSet…,(这里我们先不考虑Map接口下面的类)每种容器都有自己的特点,ArrayList底层维护的是一个数组;LinkedList是链表结构的;HashSet依赖的是哈希表,每种容器都有自己特有的数据结构。
      正是因为容器的内部结构不同,所以很多时候可能不知道该怎样去遍历一个容器中的元素。所以为了使对容器内元素的操作更为简单,Java引入了迭代器模式,把迭代抽取为一个接口,更为简洁高效的实现容器的遍历!
      把访问逻辑从不同类型的集合类中抽取出来,从而避免向外部暴露集合的内部结构,达到设计人员无需关心容器对象的内存分配的实现细节的目的。

    查看Iterator接口源码,发现Iterator主要有三个方法:hasNext()、next()、remove()
    Java迭代器Iterator知识点浅析 - 图1
    Java迭代器Iterator知识点浅析 - 图2
    Java迭代器Iterator知识点浅析 - 图3

    我们以一个具体的类来看迭代器的原理和实现过程(以ArrayList为例)
    1、hasNext()方法
    Java迭代器Iterator知识点浅析 - 图4  可以看到,hasNext方法官方说明是判断是否存在下一个元素,这里通过cursor是否与集合中的元素个数相同来判断集合中元素是否遍历完毕,如果没有,就返回true。

    2、next()方法
    Java迭代器Iterator知识点浅析 - 图5
      注意:这里新创建的迭代器默认指向列表中的第一个元素!!!
      这里调用next()方法,是返回当前元素, 指针(cursor)并指向下一个元素。这里跟我们前面那个Iterator那里的说法我觉得是有点冲突的—-Returns the next element in the iteration.(其实我这里也没品出来,不过我们清楚源码怎么实现就行了,网上各有各的说法,有的说返回当前,有的说返回下一个,与其说这么多,不如看看源码怎么实现)
    Java迭代器Iterator知识点浅析 - 图6

    3、remove()方法
    Java迭代器Iterator知识点浅析 - 图7
      remove()删除next方法返回的元素,一般和next方法一起用。这里注意如果调用remove之前没有调用next是不合法的,会抛出IllegalStateException。迭代器的remove操作删除的是最近一次由next操作获取的元素,而不是当前游标所指向的元素

    这里插着讲一下,Iterator遍历时不可以删除集合中的元素问题
      在使用Iterator的时候禁止对所遍历的集合进行改变其大小结构的操作。例如: 在使用Iterator进行迭代时,如果对集合进行了add、remove操作就会出现ConcurrentModificationException异常,除非通过迭代器自身的remove或add方法(比如ListIterator中的add方法)从结构上对列表进行修改。

    原因是因为在你迭代之前,迭代器已经被创建出来了(比如Iterator it = list.iterator();),如果在迭代的过程中,又对list进行了改变其集合大小的操作,那么Java就会给出异常。因为此时Iterator对象已经无法主动同步list做出的改变,Java会认为你做出这样的操作是线程不安全的,就会给出善意的提醒(抛出ConcurrentModificationException异常)

    实现过程就是通过checkForComodification()方法,具体实现可以详细看源码!
    Java迭代器Iterator知识点浅析 - 图8

    这里附上一位博主的详细解释:深入理解Java中的迭代器

    Java迭代器Iterator知识点浅析 - 图9

    文章末尾附上ArrayList中迭代器一段详细源码

    1. private class Itr implements Iterator<E> {
    2. int cursor; // index of next element to return
    3. int lastRet = -1; // index of last element returned; -1 if no such
    4. int expectedModCount = modCount;
    5. // prevent creating a synthetic constructor
    6. Itr() {}
    7. public boolean hasNext() {
    8. return cursor != size;
    9. }
    10. @SuppressWarnings("unchecked")
    11. public E next() {
    12. checkForComodification();
    13. int i = cursor;
    14. if (i >= size)
    15. throw new NoSuchElementException();
    16. Object[] elementData = ArrayList.this.elementData;
    17. if (i >= elementData.length)
    18. throw new ConcurrentModificationException();
    19. cursor = i + 1;
    20. return (E) elementData[lastRet = i];
    21. }
    22. public void remove() {
    23. if (lastRet < 0)
    24. throw new IllegalStateException();
    25. checkForComodification();
    26. try {
    27. ArrayList.this.remove(lastRet);
    28. cursor = lastRet;
    29. lastRet = -1;
    30. expectedModCount = modCount;
    31. } catch (IndexOutOfBoundsException ex) {
    32. throw new ConcurrentModificationException();
    33. }
    34. }
    35. @Override
    36. public void forEachRemaining(Consumer<? super E> action) {
    37. Objects.requireNonNull(action);
    38. final int size = ArrayList.this.size;
    39. int i = cursor;
    40. if (i < size) {
    41. final Object[] es = elementData;
    42. if (i >= es.length)
    43. throw new ConcurrentModificationException();
    44. for (; i < size && modCount == expectedModCount; i++)
    45. action.accept(elementAt(es, i));
    46. // update once at end to reduce heap write traffic
    47. cursor = i;
    48. lastRet = i - 1;
    49. checkForComodification();
    50. }
    51. }
    52. final void checkForComodification() {
    53. if (modCount != expectedModCount)
    54. throw new ConcurrentModificationException();
    55. }
    56. }