java中的迭代器

597 阅读2分钟

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的设计思想,它把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构,不同的集合可以在内部实现自己不同的遍历操作。