1.迭代器模式简介
所有的java程序员对Iterator都不陌生,只要是Collection,就都可以通过iterator()方法来获取迭代器Iterator,从而访问集合中的元素。迭代器模式(Iterator Pattern)是行为型(Behavioral)设计模式,为集合类提供了遍历集合元素的行为。
迭代器模式一共有四种角色:
(1) Iterator(抽象迭代器):它定义了访问和遍历元素的接口,声明了用于遍历数据元素的方法。
(2) ConcreteIterator(具体迭代器):它实现了抽象迭代器接口,完成对集合对象的遍历。
(3) Aggregate(抽象聚合类):它用于存储和管理元素对象,声明了获取Iterator的抽象方法
(4) ConcreteAggregate(具体聚合类): 实现了抽象聚合类中声明的获取Iterator的方法,返回具体迭代器。
2. 迭代器模式举例
下面我们模拟JDK源码中的一些类,来分析演示迭代器模式。
序号 | 类名 | 角色 | 说明 |
---|---|---|---|
1 | MyIterator | Iterator | 抽象迭代器 |
2 | Itr | ConcreteIterator | 具体迭代器,是MyArrayList的私有内部类 |
3 | MyCollection | Aggregate | 抽象聚合类,是集合类的接口。 |
4 | MyArrayList | ConcreteAggregate | 具体聚合类,是一种有序的、可重复的元素集合 |
5 | IteratorMain | 客户端 | 演示调用 |
1. MyIterator
我们首先来看MyIterator,它一般包括3个方法,分别是判断是否还有更多的元素、得到下一个元素、删除最后一个被遍历的元素。
public interface MyIterator<E> {
// 是否还有更多的元素。
boolean hasNext();
// 得到下一个元素。
E next();
// 删除最后一个被遍历的元素,必须要在next()执行后才可以执行。
void remove();
}
2. MyCollection
MyCollection接口中定义了获取迭代器的方法,另外,我们只选取了add和remove方法,用来解释迭代器设计模式足够了。
public interface MyCollection<E> {
// 增加元素
boolean add(E e);
// 删除元素
boolean remove(Object o);
// 获取迭代器
Iterator<E> iterator();
}
3. ArrayList 和 它的迭代器 Itr
public class MyArrayList<E> implements MyCollection {
// 存储ArrayList 中的元素
transient Object[] elementData;
/**
* 当前集合中元素的数目
*/
private int size;
/**
* 为了演示方便,设置定长的数组
*/
public MyArrayList() {
this.elementData = new Object[1024];
}
/**
* 把指定的对象添加到集合中。仅仅是演示,不考虑数组越界的情况。
*
* @param o 指定的对象
* @return true,如果添加成功的话
*/
@Override
public boolean add(Object o) {
elementData[size++] = o;
return true;
}
/**
* 如果对象在ArrayList中存在,就移除它。
*
* @param o 指定移除的对象
* @return true,如果集合中包含指定的对象
*/
@Override
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index + 1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
/**
* 获取集合的迭代器
*
* @return MyIterator
*/
@Override
public MyIterator iterator() {
return new Itr();
}
// ***** 内部类,迭代器 ***** //
private class Itr implements MyIterator<E> {
// 下一个元素的游标。
int cursor;
// 上一个返回的元素的index,-1代表没有这样的index。
int lastRet = -1;
/**
* 判断集合 是否还有更多的元素
*
* @return true:有;false: 没有
*/
@Override
public boolean hasNext() {
return cursor != size;
}
/**
* 获取集合中的下一个元素
*
* @return E 下一个元素
*/
@Override
public E next() {
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = MyArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
/**
* 移除上一个被访问的元素
*/
@Override
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
try {
MyArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
}
**4. 演示类 **
public class IteratorMain {
public static void main(String[] args) {
System.out.println("初始化MyArrayList");
MyArrayList<Integer> arrayList = new MyArrayList<>();
for (int i = 0; i < 10; i++) {
arrayList.add(i);
}
System.out.println("移除一条数据");
MyIterator<Integer> iterator = arrayList.iterator();
if(iterator.hasNext()){
Integer i = iterator.next();
System.out.println(i);
iterator.remove();
}
System.out.println("遍历集合中的数据");
while (iterator.hasNext()){
Integer i = iterator.next();
System.out.println(i);
}
}
}
3. 总结
迭代器模式简化了集合的遍历方式,迭代器通常也是和集合类共生出现的;Java的中集合类中都提供了迭代器,实际的应用中使用到迭代器模式并不是很多。
4. 拓展
访问集合中的元素,有两种方法,一种是顺序访问,一种是随机访问;不同的集合类,可能使用不同的访问方式。以java.util.ArrayList
为例,它可以通过public Iterator<E> iterator()
方法获得迭代器,从而调用Iterator.next
来顺序访问集合元素;同时,它还实现了java.util.RandomAccess
接口,可以通过public E get(int index)
方法来随机访问集合元素。
对于实现了随机访问的集合类,即实现了RandomAccess接口的类,比如ArrayList,使用fori循环,要比Iterator快。
// 对于实现RandomAccess的类,这样循环效率更高。
for (int i = 0; i < list.size(); i++)
list.get(i);
// 对于实现RandomAccess的类,Iterator循环效率不如上面。
for (Iterator i=list.iterator(); i.hasNext(); )
i.next();
对于没有实现随机访问的集合类,例如LinkedList,fori循环速度要比for iterator要慢。
(完)