Iterator<E>
是一个接口,所以具体的实现需要看其中的实现类。下面就挑选其中比较简单的一个实现类来分析一下。
java.util.AbstractList.Itr 分析
// java.util.AbstractList.Itr
private class Itr implements Iterator<E> {
/**
* Index of element to be returned by subsequent call to next.
*/
int cursor = 0;
/**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
*/
int lastRet = -1;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
这个类是一个内部类,并不是独立存在的。但是不妨碍对其进行独立分析。
这个类的代码很简单。
- 首先要注意到:
cursor
的默认值是0
,lastRet
的默认值是-1
,而expectedModCount
的默认值是modCount
。
然后,开始看具体的方法:
hasNext()
这个方法很明确,判断还能不能通过next()
获取一个元素了。实现更是简单return cursor == size();
从这个方法可以看出cursor
很重要,是跟集合的长度对等的。但是目前没有看到怎么操作cursor
这个变量的。
-
next()
public E next() { checkForComodification(); // 这个先不管 try { int i = cursor; // 比如当前是第一次调用,则 i = cursor = 0 E next = get(i); // 获取第一个元素 lastRet = i; // lastRet = 0; cursor = i + 1; // cursor = 1 return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } }
这个方法就是根据cursor
所在位置,获取集合中对应位置的元素的get(cursor)
。然后,cursor += 1;
这样下次next()
获取到的就是get(i+1)
了。很符合逻辑。同时这里设置了lastRet = cursor;
,在 cursor +=1;
之前。这个赋值是为了remove()
的。
remove()
public void remove() {
if (lastRet < 0) // 默认 lastRet == -1 ,也就是说 remove() 必须是在 next() 之后调用
throw new IllegalStateException();
checkForComodification(); // 先不管这个
try {
AbstractList.this.remove(lastRet); // 移除集合中,上次 next() 对应的元素
if (lastRet < cursor) // 每次 next() 都会让 lastRet == cursor -1;
cursor--;
lastRet = -1; // 移除成之后,lastRet 再次回到默认值 -1
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
这个方法也很明白了。首先可以看到如果没有执行过next()
, 直接remove()
会抛异常。因为没对象让你移除。然后,每次移除完成之后,lastRet = -1
, 又回到了,next()
之前的状态。也就意味着。每次 remove()
之前都必须调用一次next()
,否则报错。
checkForComodification()
略
通过以上分析,可以看到一个Iterator
的大致逻辑。所以使用 Iterator
进行清空的操作都是。
// 清除集合中的元素
while(it.hasNext()) {
it.next();
it.remove();
}
java.util.AbstractList.ListItr 分析
// 继承自 Itr, Itr 有的方法,它都有
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; // 注意:不同于 next() , 此时 lastRet = cursor;
return previous;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
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; // 在 add/ remove 的时候,都会让 lastRet = -1;
cursor = i + 1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
通过以上代码可以看出:
lastRet
表示的当前获取的值的索引,或者是-1
。cursor
要分情况,如果是next()
之后,cursor
表示的当前next()
对应的元素索引index +1
, 而如果当前是previous()
,则cursor
与lastRet
都是表示当前previous()
对应的元素的索引值index
。【由于hasNext()
的实现逻辑,也限制了此时cursor
的值。】
通过 1,2 可知:如果不停的连续调用 previous(); next();
则,cursor
的值保持不变。
// abc.groovy
List<Integer> list = new ArrayList<>()
Collections.addAll(list, 11, 21, 31, 41, 51, 61, 71, 81, 91, 101)
def itr = list.listIterator(list.size())
printf("index first %d\n", itr.nextIndex())
while (itr.hasPrevious()){
println(itr)
itr.previous()
itr.next()
// println(itr)
printf("get #2 %d , %d , %d\n",
2222, itr.nextIndex(), itr.previousIndex())
} // 这是一个死循环。
println("Done\n")