Iterator<E>接口
Iterator<E>接口含有3个方法
public interface Iterator<E>{
E next();
boolean hasNext();
void remove();
}
-
next()
如果到达了集合末尾,将会抛出NoSuchElementException,因此,一般调用next()前要调用hasNext()
然而,跟C++STL的迭代器不同,STL中的迭代器是根据数据索引建模的,道理跟索引i对应a[i]元素一样,而Java迭代器被认为是位于两个元素之间,当调用next时,迭代器就越过下一个元素,并返回越过的元素的引用,有点类似“消费掉”的意思。
-
删除元素
删除上次调用next方法时返回的元素,next方法和remove方法的调用互相依赖,如果调用remove之前没有调用next是不合理的,会抛出IllegalStateException(set方法同理)
ListIterator接口
相比于Iterator,还包括add,previous,hasPrevious方法,LinkedList类就实现了此接口
previous,hasPrevious和next,hasNext同,只是一个顺着一个逆着遍历,当然,在调用remove的时候,删除的是越过的元素,而并不是说一定为迭代器左边的元素
java中的链表都是双向链表,所以会有previous,hasPrevious,add方法仅针对资源有序的集合,也就是说,add方法将会添加到当前的iterator后面,如果iterator刚创建,也就是在头结点前,此时调用add则此新节点将会变成头结点
对于set等无序集合,在iterator接口是实现add方法就没有意义,所以Collection拓展的是Iterator接口,没有包括add方法
Collection
Collection接口拓展了Iterator接口,也就是说所有的
foreach
foreach循环可以和任何实现了Iterable接口的对象一起工作,这个接口只有一个方法
public interface Iterable<E>{
Iterator<E> iterator();
}
AbstractList中Iterator的实现
在iterator接口中返回了一个内部类Itr
private class Itr implements Iterator<E> {
//下一个元素的索引位置
int cursor = 0;
//上一个元素的索引位置,这个值将会变成-1在调用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();
}
}
next()的实现是通过get(cursor)然后cursor++,通过这样实现遍历
而在remove()中,有这么一句“expectedModCount = modCount”,这是一种称为“快速失败”的机制,提供了迭代过程中集合的安全性,也就是说迭代过程中不允许修改集合
modCount记录修改此列表的次数:包括改变列表的结构,改变列表的大小,打乱列表的顺序等使正在进行迭代产生错误的结果。
每次增删操作都有modCount++,通过和expectedModCount的对比,迭代器可以快速的知道迭代过程中是否存在list.add()类似的操作,存在的话快速失败!
然而,需要注意的是,仅仅设置元素的值并不是结构的修改。
网友评论