Iterator
public interface List<E> extends Collection<E>
public interface Collection<E> extends Iterable<E>
对于Iterable()接口,内部包含了iterator的获取,和forech方法
public interface Iterable{
Iterator iterator();
void forech();
}
//Iterator接口
public interface Iterator{
boolean hasNext;
E next();
void remove();
···
}
Collection接口继承了Iterable接口,而对于每个数据结构,其内部的遍历方式不同,所以具体的子类分别定义了自己的iterator
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E>
比如ArrayListz中Iterator的遍历方式
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
比如LinkedList中的遍历方式
在LinkedList中并没有实现Iterator接口,而是只实现的ListIterator接口
对于ListIterator接口
public interface ListIterator extends Iterator{
//除了有iterator所包含的方法,还含有的其它特有方法
boolean hasPrevious();
E previous();
void set();
void add();
//也就是说ListIterator 支持修改,添加元素等操作,并且支持倒序遍历
//我们看它的一个子类
private class ListItr implements ListIterator<E> {
ListItr(int index) {
// assert isPositionIndex(index);
next = (index == size) ? null : node(index);
nextIndex = index;
}
//从它的构造方法中可以看出,ListIterator还支持从指定位置遍历
}
}
//由于LinkedList中为链表结构,所以遍历方式有所不同
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
iterator的remove操作
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
我们知道直接调用List的remove方法会产生错误,因为remove后,后面的元素会向前移动
而在Iterator的remove方法中,调用了List的remove方法后,iterator还是将cursor=lastRet,实现了对remove
操作的封装。
再看下边一行代码,lastRet=-1,又将lastRet赋值为-1;所以,必须调用了next方法,指向下一个元素后,remove方法
才会有效,不然会抛出IllegalStateException,所以Iterator的remove操作,必然在next操作之后调用。
一些思考
众多遍历方式中为什么使用Iterator?
对于LinkedList,内部为链表结构。对于下边这种操作
LinkedList list = new LinkedList();
for(int i=0;i<list.size;i++){
list.get(i);
}
它的时间复杂度为O(n^2),而如果使用iterator,它的时间复杂度为O(n)
实际上为了提高查找效率,linkedList中采用了简单二分查找元素。
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
还有就是Iterator的设计思想,它把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构,不同的集合可以在内部实现自己不同的遍历操作。