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接口,而对于每一个数据结构,其内部的遍历方式不一样,因此具体的子类分别定义了本身的iteratornode
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E>
复制代码
好比ArrayListz中Iterator的遍历方式bash
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;
}
复制代码
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,内部为链表结构。对于下边这种操做ui
LinkedList list = new LinkedList();
for(int i=0;i<list.size;i++){
list.get(i);
}
复制代码
它的时间复杂度为O(n^2),而若是使用iterator,它的时间复杂度为O(n)
实际上为了提升查找效率,linkedList中采用了简单二分查找元素。this
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的设计思想,它把访问逻辑从不一样类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构,不一样的集合能够在内部实现本身不一样的遍历操做。spa