本文主要讲解迭代器模式在ArrayList源码中的使用。
迭代器模式(Iterator Pattern):提供一种方法来访问聚合对象中的各个元素,而不用暴露这个对象的内部表示。在java中,ArrayList的迭代器有两种 Iterator 和 ListIterator。
Iterator
Iterator主要作用是遍历对象。Java的Iterator只能单向移动。
Iterator demo
public class ArrayListDemo {
public void demo(){
//0.构造ArrayList,添加数据
List list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
//1. 获得指向list开始处的迭代器
Iterator iterator = list.iterator();
//2. hasNext(),检查序列中向下是否还有元素
while (iterator.hasNext()){
//3. next(),获取序列中的下个元素
String str = (String) iterator.next();
System.out.println(str);
//4. 将迭代器最后返回的一个元素删除。同时意味着 迭代器调用remove()需要先调用next()
iterator.remove();
}
System.out.println(list.size());
}
public static void main(String[] args) {
new ArrayListDemo().demo();
}
}
运行结果
D:\soft_work\java\jdk1.8.0_91...
a
b
c
d
0
ArrayList中Iterator的实现
在设计模式-01-迭代器模式中讲过,迭代器模式中有四个角色:
- 抽象聚合类Aggregate。在ArrayList的Iterator迭代器实现中,没有抽象聚合类,虽然ArrayList实现了AbstractList和List,但它向外部提供的创建迭代器的方法iterator()是ArrayList自己的。
- 具体聚合类ConcreteAggregate。在ArrayList的Iterator迭代器实现中,就是指的ArrayList本身。(聚合类主要承载数据这个功能)
- 抽象迭代器Iterator。ArrayList的实现中,值得是Iterator接口。
- 具体迭代器ConcreteIterator,ArrayList的实现中,指的是私有类Itr。
ArrayList-Iterator的常规实现
接口Iterator
package java.util;
import java.util.function.Consumer;
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
/*
* @since 1.8
*/
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
Iterator的常规实现Itr
public class ArrayList<E>
{
........
/**
* 保存添加到ArrayList中的元素。
* ArrayList的容量就是该数组的长度。
* 该值为DEFAULTCAPACITY_EMPTY_ELEMENTDATA 时,当第一次添加元素进入ArrayList中时,数组将扩容值DEFAULT_CAPACITY。
* 被标记为transient,在对象被序列化的时候不会被序列化。
*/
transient Object[] elementData;
// ArrayList的实际大小(数组包含的元素个数)。
private int size;
/**
* 返回一个用来遍历ArrayList元素的Iterator迭代器
*/
public Iterator<E> iterator() {
return new Itr();
}
/**
* AbstractList.Itr的最优化的版本
*/
private class Itr implements Iterator<E> {
int cursor; // 下一个要返回的元素的索引
int lastRet = -1; // 最近的被返回的元素的索引; 如果没有返回-1。
int expectedModCount = modCount;
/**
* 判断是否有下一个元素
*/
public boolean hasNext() {
//如果下一个要返回的元素的索引不等于ArrayList的实际大小,则返回false
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;
return (E) elementData[lastRet = i];
}
/**
* 删除最近的一个被返回的元素
* 如果迭代器没有调用next(),此时lastRet=-1,调用remove()时会产生IllegalStateException异常。
*/
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();
}
}
@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();
}
}
........
}
双向遍历ListIterator–Iterator的高级实现
ListIterator是一个更加强大的Iterator的子类型(ArrayList中,ListIterator继承了Itr)。
它只能用于各种List类的访问。
它最大的优点是可以双向移动。
它还可以产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引,并且可以使用set()方法替换它访问过的最后一个元素。
ListIterator用例
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class TestArrayList {
public void test(){
List list = new ArrayList<String>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
ListIterator iterator = list.listIterator();
System.out.println("--------------------向下遍历--------------------");
while (iterator.hasNext()){
int nextIndex = iterator.nextIndex();
String nextValue = (String) iterator.next();
// int previousIndex = iterator.previousIndex(); //此时previousIndex与nextIndex的值相同。
System.out.println("当前元素:"+nextValue+",当前元素索引: "+nextIndex);
}
System.out.println("--------------------向上遍历--------------------");
while (iterator.hasPrevious()){
int nowIndex = iterator.previousIndex();
String nowValue = (String) iterator.previous();
System.out.println("当前元素:"+nowValue+",当前元素索引:"+nowIndex);
}
System.out.println("-----------测试set()和listIterator(n)----------");
System.out.println(list);
iterator = list.listIterator(3);
while(iterator.hasNext()){
iterator.next();
iterator.set("5");
}
System.out.println(list);
}
public static void main(String[] args) {
new TestArrayList().test();
}
}
运行结果
--------------------向下遍历--------------------
当前元素:1,当前元素索引: 0
当前元素:2,当前元素索引: 1
当前元素:3,当前元素索引: 2
当前元素:4,当前元素索引: 3
--------------------向上遍历--------------------
当前元素:4,当前元素索引:3
当前元素:3,当前元素索引:2
当前元素:2,当前元素索引:1
当前元素:1,当前元素索引:0
-----------测试set()和listIterator(n)----------
[1, 2, 3, 4]
[1, 2, 3, 5]
备注:演示代码部分,如果将“向上遍历”部分注释,结果如下
--------------------向下遍历--------------------
--------------------向上遍历--------------------
-----------测试set()和listIterator(n)----------
[1, 2, 3, 4]
[1, 2, 3, 5]
原因:listIterator()返回的迭代器指向的是list的第一个元素,如果直接调用previous(),因为第一个元素之前不可能存在元素,所以直接进行向上遍历,需要给迭代器方法设置非0的初始位置才可以。
如:ListIterator iterator = list.listIterator(2);遍历index 2 之前的所有数据。
所以 如果向上遍历所有的数据 : ListIterator iterator = list.listIterator(list.size());
向下遍历所有数据: ListIterator iterator = list.listIterator();
方法
- listIterator(),iterator()用来从容器对象中返回一个指向list开始处的迭代器。
- listIterator(n),iterator(n)用来从容器对象中返回一个指向list索引为n的迭代器。
- next(),获取序列中的下个元素,运行后索引+1。
- previous(),获取列表中的上个元素,运行后索引-1。
- nextIndex(),获取序列中下个元素的索引
- previousIndex(),获取序列中上个元素的索引
- hasNext(),检查序列中向下是否还有元素
- hasPrevious(),检查序列中向上是否还有元素
- remove(),从列表中删除next()或previous()返回的最后一个元素。这也意味着调用remove()需要先调用next()或者previous()
- add(E e),将指定元素插入列表,插入位置为迭代器当前位置之前。
- set(E e),将列表中将next()或者previous()返回的最后一个元素更改为指定元素e
ListIterator 实现
在设计模式-01-迭代器模式这一文章中曾讲过,迭代器模式中有四个角色:
- 抽象聚合类Aggregate。在ArrayList的ListIterator迭代器实现中,没有抽象聚合类。虽然它实现了AbstractList,实现了List,但它向外部提供的创建迭代器的方法listIterator()是它自己的。
- 具体聚合类ConcreteAggregate。在ArrayList的ListIterator迭代器实现中,指的是ArrayList。
- 抽象迭代器Iterator。在ArrayList的ListIterator迭代器实现中,指的是ListIterator。
- 具体迭代器ConcreteIterator。在ArrayList中的ListIterator迭代器实现中,指的是ListItr
ArrayList代码片段
Iterator
import java.util.function.Consumer;
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
ListItr.java
public class ArrayList<E>
{
/**
* 保存添加到ArrayList中的元素。
* ArrayList的容量就是该数组的长度。
* 该值为DEFAULTCAPACITY_EMPTY_ELEMENTDATA 时,当第一次添加元素进入ArrayList中时,数组将扩容值DEFAULT_CAPACITY。
* 被标记为transient,在对象被序列化的时候不会被序列化。
*/
transient Object[] elementData;
// ArrayList的实际大小(数组包含的元素个数)。
private int size;
/**
* 返回一个一开始就指向列表索引为index的元素处的ListIterator
*
* @throws IndexOutOfBoundsException
*/
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
/**
* 返回一个一开始就指向列表索引为0的元素处的ListIterator
*
* @see #listIterator(int)
*/
public ListIterator<E> listIterator() {
return new ListItr(0);
}
/**
* AbstractList.ListItr的最优化版本
*/
private class ListItr extends Itr implements ListIterator<E> {
//用来从list中返回一个指向list索引为index的元素处的迭代器
ListItr(int index) {
super();
cursor = index;
}
//获取list中的上个元素
public boolean hasPrevious() {
return cursor != 0;
}
//获取list中的下个元素的索引
public int nextIndex() {
return cursor;
}
//获取list中的上个元素的索引
public int previousIndex() {
return cursor - 1;
}
//获取list中的上个元素
@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];
}
//从列表中将next()或previous()返回的最后一个元素返回的最后一个元素更改为指定元素e
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;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
}
ArrayList总结:
- 内容主要有三个关键点: 扩容、迭代器的两种实现实现 itr和listIterator、以及其它部分