Java 中的迭代器 ListIterator
一、接口源码
1 | package java.util; |
上面的所有方法中,分为查询操作和修改操作。
- 查询操作
hasNext()
next()
hasPrevious()
previous()
nextIndex()
previousIndex()
- 修改操作
remove()
set()
add()
ListIterator
是一个针对列表的迭代器,它允许程序员以任一方向遍历列表,在迭代过程中修改列表,并获取迭代器在列表中的当前位置。
ListIterator
没有当前元素的概念;其光标(cursor
属性)位置总是位于通过调用 previous()
方法返回的元素和通过调用 next()
方法返回的元素之间。这一点与 Iterator
有较大的区别,Iterator
的光标位置总是处于元素上的,而不是元素之间。对于一个长度为 n 的列表的迭代器,它有 n+1 个可能的光标位置。remove()
和 set()
方法并不是根据光标位置来定义的;它们被定义为对通过调用 next()
或 previous()
方法返回的最后一个元素进行操作。
nextIndex()
方法返回后续调用 next()
方法时将返回的元素的索引。如果迭代器位于列表的末尾,则会返回列表大小。
previousIndex()
方法返回后续调用 previous()
方法时将返回的元素的索引。如果迭代器位于列表的开头,则会返回 -1
remove()
方法会从列表中删除 next()
或 previous()
方法返回的最后一个元素(可选操作)。每次调用一次 next()
或 previous()
方法,只能调用一次 remove()
方法。只有在最后一次调用 next()
或 previous()
方法之后没有调用过 add()
方法时才可以调用 remove()
方法。
set()
方法,将 next()
或 previous()
返回的最后一个元素替换为指定的元素。只有在最后一次调用 next()
或 previous()
方法之后没有调用过 add()
或 remove()
方法时才可以调用 set()
方法。
add()
方法,将指定元素插入列表中。该元素被插入到 next()
方法返回的元素之前(如果元素存在的话),以及 previous()
方法返回的元素之后(如果元素存在的话)。如果列表中不包含任何元素,则新元素将成为列表中的唯一元素。新元素被插入之后,对 next()
的后续调用不会产生影响,对 previous()
方法的后续调用将返回新插入的元素。
这个调用会使 nextIndex 或 previousIndex 调用返回的值增加一。
二、实现
List
接口中定义了返回列表迭代器的方法:
ListIterator<E> listIterator();
方法,用来返回ListIterator<E> listIterator(int index);
方法,返回从列表指定位置开始的列表迭代器。方法指定的索引位置为初次调用next()
方法返回的第一个元素的位置。对previous()
方法的初次调用将返回指定索引位置减1位置处的元素。
1、AbstractList 中的实现
1 | public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> { |
listIterator() 方法返回一次自索引位置 0 开始的列表迭代器
方法返回一个从方法参数指定位置开始的列表迭代器
1.1 私有内部类 ListItr
列表迭代器实现
ListItr
是另一个内部类 Itr
的扩展,ListItr
依赖于列表的 get(int)
、set(int, E)
、add(int, E)
和 remove(int)
方法。
请注意,除非列表的 remove(int)
、set(int, E)
和 add(int, E)
方法被重写,否则由此实现返回的列表迭代器将在其 remove
、set
和 add
方法被调用时抛出 UnsupportedOperationException
。
另外,就像 modCount
字段的规范描述的那样,当面对并发修改时,此实现可以引发运行时异常。
1.1.1 查询方法
因为 ListIterator
中光标位置概念与 Iterator
中光标(cursor
属性)位置概念上的差别,在这里再说明一下:ListIterator
的光标位置总是位于通过调用 previous()
方法返回的元素和通过调用 next()
方法返回的元素之间。这一点与 Iterator
不同,后者的光标位置总是处于元素上的,而不是元素之间。
基于上面的光标位置的定义,涉及到根据光标位置的查询接口的实现与 Iterator
中的实现将完全不同。
1.1.2 set
方法
set()
方法中,会根据迭代器中的 lastRet
属性来修改列表底层数组中指定位置的元素。
在方法开头会判断 lastRet
的值是否为 -1,也就是说在执行了迭代器的 remove()
、add()
方法之后是不能紧接着调用 set()
方法的,因为 remove()
、add()
方法会修改列表结构并将 lastRet
迭代器的 lastRet
属性赋值为 -1
因为是根据 lastRet
属性确定的要赋值的列表索引的位置,所以 next(
) 方法和 previous()
方法是可以多次调用的,且 set()
方法修改元素的索引位置将是最后一次调用 next()
方法和 previous()
和方法的位置。
set()
方法会调用实现类列表的 set()
方法,在赋值完成之后会将列表的 modCount
的值赋值给 expectedModCount
1.1.3 add
方法
列表迭代器的 add
方法会调用列表对象的 add
方法,列表对象的 add
方法会在指定索引位置插入指定元素,并将当前位于位置的元素及其所有的后续袁旭向后移动一位(索引加一)。
列表迭代器的 add()
方法,会将元素插入到 next()
方法返回的元素之前(如果元素存在的话),以及 previous()
方法返回的元素之后(如果元素存在的话)的位置,该位置是根据光标所处位置决定的(cursor
属性),基于 Iterator
和 ListIterator
中光标(cursor
属性)位置概念的差异。如果列表中不包含任何元素,则新元素将成为列表中的唯一元素。
新元素被插入之后,对 next()
的后续调用不会产生影响,对 previous()
方法的后续调用将返回新插入的元素。
2、ArrayList 中的实现
对于 ArrayList
中列表迭代器的实现,是针对 AbstractList
中的实现的优化。优化方面与 ArrayList.Iterator
迭代器相同,因为 ArrayList
是列表的完全实现,所以抽象列表 AbstractList
方法中存在的对列表对象 get
方法的调用。
在这里就不做过多介绍了。
3、LinkedList 中的实现
。。。。。。
相关链接
OB links
[[迭代器 Iterator]]
OB tags
#Java