
1. 引言在 Java 集合框架中Iterator是遍历集合元素的标准接口但它有一个明显的局限——只能单向遍历。当我们需要在遍历过程中反向移动、获取上一个元素或在遍历时安全地修改列表时Iterator就显得力不从心了。ListIterator接口正是为解决这些问题而生。它是Iterator的子接口专门为List系列集合如ArrayList、LinkedList提供双向遍历和列表修改的能力。本文将深入剖析ListIterator的源码设计、核心方法、使用场景与注意事项帮助你彻底掌握这一利器。2. ListIterator 接口概览2.1 接口定义ListIterator位于java.util包中其接口定义如下publicinterfaceListIteratorEextendsIteratorE{// 查询操作booleanhasNext();Enext();booleanhasPrevious();Eprevious();intnextIndex();intpreviousIndex();// 修改操作voidremove();voidset(Ee);voidadd(Ee);}2.2 与 Iterator 的关系ListIterator继承了Iterator的全部方法hasNext、next、remove并在此基础上扩展了 6 个新方法。它只能用于List及其子类而Iterator可以用于所有Collection。特性IteratorListIterator遍历方向单向向后双向向前/向后获取前一个元素不支持支持previous()获取索引不支持支持nextIndex()/previousIndex()修改元素仅支持删除支持删除、替换、新增适用集合所有 Collection仅 List3. 核心方法详解3.1 双向遍历方法ListIterator最核心的特性就是双向遍历。与Iterator只能通过next()向后移动不同ListIterator可以通过previous()向前移动。ListStringlistnewArrayList(Arrays.asList(A,B,C,D));ListIteratorStringitlist.listIterator();// 向后遍历System.out.println(向后遍历);while(it.hasNext()){System.out.print(it.next() );}// 输出A B C D// 此时迭代器位于列表末尾可以向前遍历System.out.println(\n向前遍历);while(it.hasPrevious()){System.out.print(it.previous() );}// 输出D C B A3.2 索引访问方法nextIndex()返回下一次调用next()将返回的元素的索引previousIndex()返回下一次调用previous()将返回的元素的索引。这两个方法在需要定位操作时非常有用。ListStringlistnewArrayList(Arrays.asList(A,B,C));ListIteratorStringitlist.listIterator();System.out.println(nextIndex: it.nextIndex());// 0System.out.println(previousIndex: it.previousIndex());// -1it.next();// 移动到 ASystem.out.println(nextIndex: it.nextIndex());// 1System.out.println(previousIndex: it.previousIndex());// 03.3 修改方法set 与 addset(E e)用于替换最近一次由next()或previous()返回的元素add(E e)用于在当前迭代位置插入新元素。ListStringlistnewArrayList(Arrays.asList(A,B,C));ListIteratorStringitlist.listIterator();it.next();// 指向 Ait.set(X);// 将 A 替换为 XSystem.out.println(list);// [X, B, C]it.add(Y);// 在 X 之后插入 YSystem.out.println(list);// [X, Y, B, C]4. 获取 ListIterator 的三种方式List接口提供了三种获取ListIterator的方法各有适用场景ListStringlistnewArrayList(Arrays.asList(A,B,C));// 方式一从列表头部开始ListIteratorStringit1list.listIterator();// 方式二从指定索引开始ListIteratorStringit2list.listIterator(1);// 从索引 1元素 B开始// 方式三从列表尾部开始通过 listIterator(size)ListIteratorStringit3list.listIterator(list.size());// 从末尾开始可向前遍历5. 实战案例5.1 反向遍历列表ListIntegernumbersnewArrayList(Arrays.asList(1,2,3,4,5));// 从末尾获取迭代器实现反向遍历ListIteratorIntegeritnumbers.listIterator(numbers.size());System.out.print(反向遍历);while(it.hasPrevious()){System.out.print(it.previous() );}// 输出5 4 3 2 15.2 遍历时安全地替换元素ListIntegernumbersnewArrayList(Arrays.asList(1,2,3,4,5));ListIteratorIntegeritnumbers.listIterator();while(it.hasNext()){intnumit.next();if(num%20){it.set(num*10);// 将偶数放大 10 倍}}System.out.println(numbers);// [1, 20, 3, 40, 5]5.3 在指定位置插入元素ListStringlistnewArrayList(Arrays.asList(A,C));ListIteratorStringitlist.listIterator();it.next();// 指向 Ait.add(B);// 在 A 之后插入 BSystem.out.println(list);// [A, B, C]6. 注意事项与常见陷阱6.1 并发修改异常与Iterator一样在使用ListIterator遍历时如果通过非迭代器方式如list.add()、list.remove()修改列表会抛出ConcurrentModificationException。ListStringlistnewArrayList(Arrays.asList(A,B,C));ListIteratorStringitlist.listIterator();while(it.hasNext()){Stringsit.next();if(s.equals(B)){list.remove(B);// 错误应使用 it.remove()}}// 抛出 ConcurrentModificationException6.2 set 与 remove 的调用限制set和remove方法都要求最近一次调用必须是next()或previous()。如果先调用了add()再调用set()或remove()会抛出IllegalStateException。ListStringlistnewArrayList(Arrays.asList(A,B));ListIteratorStringitlist.listIterator();it.next();// 合法it.add(X);// 插入后迭代器状态改变it.set(Y);// 抛出 IllegalStateException6.3 add 方法对迭代器位置的影响调用add()后新元素被插入到迭代器当前位置之前且next()返回的元素不变但previous()会返回新插入的元素。ListStringlistnewArrayList(Arrays.asList(A,C));ListIteratorStringitlist.listIterator();it.next();// 返回 Ait.add(B);// 插入 BSystem.out.println(it.previous());// 返回 BSystem.out.println(it.next());// 返回 C7. 源码视角ArrayList 中的 ListIterator 实现以ArrayList为例其内部类ListItr实现了ListIterator接口。核心字段包括privateclassListItrextendsItrimplementsListIteratorE{// 游标位置即下一个 next() 返回元素的索引privateintcursor;// 最近一次返回元素的索引-1 表示没有privateintlastRet-1;// 期望的修改次数用于快速失败检测privateintexpectedModCountmodCount;}add方法的实现体现了其位置语义publicvoidadd(Ee){checkForComodification();try{inticursor;ArrayList.this.add(i,e);// 在游标位置插入cursori1;// 游标后移lastRet-1;// 重置 lastRetexpectedModCountmodCount;}catch(IndexOutOfBoundsExceptionex){thrownewConcurrentModificationException();}}8. 总结ListIterator是 Java 集合框架中一个功能强大的接口它弥补了Iterator单向遍历的不足提供了双向遍历、索引访问和列表修改三大核心能力。在实际开发中当你需要反向遍历列表、在遍历时替换或插入元素时ListIterator是最佳选择。掌握ListIterator的关键在于理解其游标语义next()与previous()如何移动游标、set()与remove()的调用前提、以及add()对游标位置的影响。希望本文能帮助你更好地理解和使用这一接口写出更优雅、更高效的 Java 代码。