一、接口源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package java.util;

/**
* @since 1.2
*/
public interface ListIterator<E> extends Iterator<E> {

boolean hasNext();

E next();

boolean hasPrevious();

E previous();

int nextIndex();

int previousIndex();

void remove();

void set(E e);

void add(E e);
}

上面的所有方法中,分为查询操作和修改操作。

  • 查询操作
    • 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {

public ListIterator<E> listIterator() {
return listIterator(0);
}

public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);

return new ListItr(index);
}

private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
cursor = index;
}

public boolean hasPrevious() {
return cursor != 0;
}

public E previous() {
checkForComodification();
try {
int i = cursor - 1;
E previous = get(i);
lastRet = cursor = i;
return previous;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException(e);
}
}

public int nextIndex() {
return cursor;
}

public int previousIndex() {
return cursor-1;
}

public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();

try {
AbstractList.this.set(lastRet, e);
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}

public void add(E e) {
checkForComodification();

try {
int i = cursor;
AbstractList.this.add(i, e);
lastRet = -1;
cursor = i + 1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}

private void rangeCheckForAdd(int index) {
if (index < 0 || index > size())
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
}

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) 方法被重写,否则由此实现返回的列表迭代器将在其 removesetadd方法被调用时抛出 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 属性),基于 IteratorListIterator 中光标(cursor属性)位置概念的差异。如果列表中不包含任何元素,则新元素将成为列表中的唯一元素。

新元素被插入之后,对 next() 的后续调用不会产生影响,对 previous() 方法的后续调用将返回新插入的元素。

2、ArrayList 中的实现

对于 ArrayList 中列表迭代器的实现,是针对 AbstractList 中的实现的优化。优化方面与 ArrayList.Iterator 迭代器相同,因为 ArrayList 是列表的完全实现,所以抽象列表 AbstractList 方法中存在的对列表对象 get 方法的调用。

在这里就不做过多介绍了。

3、LinkedList 中的实现

。。。。。。

相关链接

[[迭代器 Iterator]]

OB tags

#Java