迭代器Iterator源码分析

我们在遍历一个集合对象时经常会使用到迭代器Iterator,它提供给我们获取、删除集合中元素的功能。Iterator包含三个方法,分别是:
1、hasNext(),用于判断迭代器是否已从头到尾将集合遍历了一遍,后面是否还有元素。
2、next(),用于获取当前指向的元素。
3、remove(),删除刚刚访问过的元素。
接下来简单讲一下Iterator与抽象类AbstractList,接口List、Collection的关系,接口Collection继承了接口Iterable,从而覆盖了Iterable接口中的方法iterator(),而接口List继承了Collection,接着AbstractList抽象类实现了接口List,我们看看AbstractList类中对方法iterator()的定义:

public Iterator<E> iterator() {
	return new Itr();
    }

该方法返回了一个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 {
		E next = get(cursor);
		lastRet = cursor++;
		return next;
	    } catch (IndexOutOfBoundsException e) {
		checkForComodification();
		throw new NoSuchElementException();
	    }
	}

	public void remove() {
	    if (lastRet == -1)
		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();
	}
    }

Itr类实现了接口Iterator,对hasNext(),next(),remove()三个方法进行了定义,首先来看看类的三个属性。

用于记录当前迭代器遍历到的位置,通过该属性访问元素
int cursor = 0;
该属性用于记录上一次使用next()方法时遍历所在的位置,在调用remove方法后该属性值变回-1
int lastRet = -1;
modCount是ArrayList的属性,用于记录对集合进行操作的次数,包括add、remove等方法。expectedModCount的应用是为了实现一种”快速失败"机制,即在使用迭代器的过程中如果对原集合(如ArrayList)进行了修改,此时modCount的值将会发生变化,二者不再相同,此时将会抛出并发修改异常。ConcurrentModificationException
int expectedModCount = modCount;

理解了几个属性之后我们再来看看三个方法:
1、hasNext()

public boolean hasNext() {
            return cursor != size();
	}

调用集合的size()方法,返回集合大小,通过将现阶段访问位置与集合大小进行对比判断迭代器后面是否还有可遍历的元素。
2、next()

public E next() {
            checkForComodification();
	    try {
		E next = get(cursor);
		lastRet = cursor++;
		return next;
	    } catch (IndexOutOfBoundsException e) {
		checkForComodification();
		throw new NoSuchElementException();
	    }
	}

首先判断是否发生并发修改异常,不是的话就调用get方法获取cursor指向位置的值,将cursor赋值给lastRet,cursor自动加1.返回获取到的对象。
3、remove()

public void remove() {
	    if (lastRet == -1)
		throw new IllegalStateException();
            checkForComodification();

	    try {
		AbstractList.this.remove(lastRet);
		if (lastRet < cursor)
		    cursor--;
		lastRet = -1;
		expectedModCount = modCount;
	    } catch (IndexOutOfBoundsException e) {
		throw new ConcurrentModificationException();
	    }
	}

该方法首先判断lastRet的值,如果等于-1,表示刚刚进行了删除操作,此时抛出不合法状态异常,接着再判断是否抛出并发修改异常,如果不,则调用集合的remove方法对lastRet指向位置的集合元素进行删除,再判断lastRet是否小于cursor,因为集合进行了删除操作,元素位置发生了变化,这一步是为了通过改变cursor的值改变迭代器指向的位置。同时,lastRet值设为-1,表示刚刚进行了删除操作,expectedModCount属性的值也进行修改,等于 modCount,以防抛出同步修改异常。

猜你喜欢

转载自blog.csdn.net/llc950819/article/details/86064154