Java 迭代
许多时候,代码要用某种方式处理集合中的每个元素,或者叫做迭代访问集合中的所有元素。比如我们迭代访问数组中的所有元素,将其依次打印出来。
为迭代数组,我们可以用 for(int i = 0; i < a.length; i++) {}
也可以用 foreach 语句 for(int i : a) {}
。
能不能让我们自己定义的数据类型也支持 foreach 迭代?
比如现在有一个自定义栈 ResizingArrayStack。如何让它支持以下操作?
ResizingArrayStack<String> collection = new ResizingArrayStack<String>();
for (String s : collection) System.out.println(s);
其实,foreach 语句只是 while 语句的一种简写方式。它本质上和以下 while 语句是等价的:
Iterator<String> i = collection.iterator();
while (i.hasNext())
{
String s = i.next();
System.out.println(s);
}
所以,要支持 foreach 迭代:
❏ 首先,ResizingArrayStack 必须实现一个 iterator() 方法,该方法返回一个 Iterator 对象;
❏ 其次,其支持的 iterator() 方法返回的 Iterator 对象必须支持两个方法:hasNext()(返回一个布尔值,用来判断是否还有下一个迭代元素)和 next()(返回 ResizingArrayStack 中的下一个迭代元素)。
Java 使用接口机制来指定一个类所必须实现的方法,要使 ResizingArrayStack 类可迭代,第一步就是让它实现 Iterable 接口,要实现 Iterable,先要在 ResizingArrayStack 类声明中加入 implements Iterable<Item>
:
public class ResizingArrayStack<Item> implements Iterable<Item>
{
...
}
然后在类中添加一个 iterator() 方法用来返回一个迭代器 Iterator<Item>,不同的可迭代类型应该有不同的迭代器,这里将 ResizingArrayStack 的迭代器命名为 ResizingArrayStackIterator。
public Iterator<Item> iterator()
{ return new ResizingArrayStackIterator(); }
迭代器是一个实现了 hasNext() 和 next() 方法的类的对象,类似地,通过实现 Iterator 接口来约定 ResizingArrayStackIterator 类必须实现这两个方法,同时我们根据数据类型的迭代要求写好 hasNext() 和 next() 中的迭代逻辑(这里省略):
private class ResizingArrayStackIterator implements Iterator<Item>
{
...
public boolean hasNext() { ... }
public Item next() { ... }
}
最后,Iterator 接口不在 java.lang 中,需要用 import java.util.Iterator;
将其导入。
所以一个可迭代的 ResizingArrayStackIterator 类应该是这样:
import java.util.Iterator;
public class ResizingArrayStack<Item> implements Iterable<Item>
{
...
public Iterator<Item> iterator()
{ return new ResizingArrayStackIterator(); }
private class ResizingArrayStackIterator implements Iterator<Item>
{
...
public boolean hasNext() { ... }
public Item next() { ... }
}
}
另,Iterator 接口中还有一个 remove() 方法,只需要用 foreach 来访问数据时可不实现。
总结自《算法(第四版)》1.3 背包、队列和栈