上一篇笔记主要是一些常用方法和相关联的方法的总结,这一篇主要记录一下迭代器相关逻辑。
数组列表的迭代器是由于集合接口继承迭代器接口决定的,迭代器接口这里就不再重复了,有记录:迭代器接口。集合类都会有返回迭代器的方法:
/** * 以正确的顺序返回此列表中元素的迭代器。 * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>. * @return an iterator over the elements in this list in proper sequence */ public Iterator<E> iterator() { return new Itr();//创建一个对象,具体逻辑在内部类中 }
迭代器方法的具体实现在 AbstractList 类中已经给出了,不过其子类型的实现细节,也就是 Itr 这个内部类会有所不同。
/** * An optimized version of AbstractList.Itr 相比较 AbstractList.Itr 这是个优化版本 */ private class Itr implements Iterator<E> { int cursor; // index of next element to return 下一个返回元素的下标 int lastRet = -1; // index of last element returned; -1 if no such 上一个返回元素的下标,如果这个元素值是 -1 int expectedModCount = modCount; Itr() {}//无参构造方法 public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") 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; //cursor + 1 return (E) elementData[lastRet = i]; //修改lastRet ,并返回该位置元素 } public void remove() { if (lastRet < 0)//调用next 方法之前调用该方法 throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1;//被删了相当于上一个没有返回,接下去的遍历修改方式是 lastRet = i = cursor 没有影响 expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } //这个方法暂时不看 @Override @SuppressWarnings("unchecked") public void forEachRemaining(Consumer<? super E> consumer) { Objects.requireNonNull(consumer); final int size = ArrayList.this.size; int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } while (i != size && modCount == expectedModCount) { consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
由以上代码可知,最重要的就是理解两个属性:cursor 和 lastRet ,两个方法:next() 和 remove()。这个迭代器返回元素顺序就是按底层数组下标从小到大依次返回的。删除方法要在next() 方法调用之后调用,而且每次只能调用一次删除方法,因为调用一次后 lastRet =-1,再次调用会抛出异常。
对于列表还有自己的列表迭代器在List 接口中定义,在 AbstractList 中提供了实现细节。看一下数组列表中的具体实现逻辑。
/** * 从列表中的指定位置开始,以适当的顺序返回在此列表中的元素上的列表迭代器。 * 指定的索引指示初始调用{@link ListIterator#next next}将返回的第一个元素。 * 初次调用{@link ListIterator#previous previous}将返回具有指定索引减一的元素。 * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>. * @throws IndexOutOfBoundsException {@inheritDoc} */ public ListIterator<E> listIterator(int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: "+index); return new ListItr(index); } /** * 返回此列表中的元素的列表迭代器(按适当顺序)。 * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>. * @see #listIterator(int) */ public ListIterator<E> listIterator() { return new ListItr(0); }两种重载形式都是调用列表迭代器有参构造方法。
/** * An optimized version of AbstractList.ListItr 优化版本 */ private class ListItr extends Itr implements ListIterator<E> { ListItr(int index) { //有参构造方法,指定下一个返回元素的下标 super(); cursor = index; } //是否还有前一位元素 public boolean hasPrevious() { return cursor != 0; } //获取下一个返回元素的下标 public int nextIndex() { return cursor; } //获取前一位返回元素的下标 public int previousIndex() { return cursor - 1; } @SuppressWarnings("unchecked") public E previous() { checkForComodification(); int i = cursor - 1; if (i < 0) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i; return (E) elementData[lastRet = i]; }//这里要注意理解 cursor 与 lastRet 的含义 public void set(E e) { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.set(lastRet, e);//调用数组列表的修改方法 } catch (IndexOutOfBoundsException ex) {//注意捕获与抛出的异常,之所以出现下标越界,是并发修改导致的 throw new ConcurrentModificationException(); } }//修改上一次返回的元素 public void add(E e) { checkForComodification(); try { int i = cursor; ArrayList.this.add(i, e); //在下一个返回元素位置添加指定元素 cursor = i + 1; //原来下一个返回元素已经右移一位,所以 cursor + 1 lastRet = -1; //新添加的元素没有迭代返回 expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } }
ListItr 继承自 Itr ,主要新增了一些新的特性:
# 支持从指定位置开始迭代返回元素
# 新增了从右到左的迭代方式
# 新增了添加和修改方法
对于迭代器 “以正确的顺序返回元素” 这一说法,在数组列表中,就是底层数组中的顺序。
来源:oschina
链接:https://my.oschina.net/u/3488841/blog/4294103