1. Iterable简介
实现此接口的对象支持迭代,允许该对象成为增强型for语句(有时称为“for-each”语句)的目标。
Iterable接口中只有一个iterator()方法(JDK8及8以后新增两个default方法),该方法返回Iterator类型对象。
public interface Iterable<T> {
Iterator<T> iterator();
...
}
2. Iterator简介
实现此接口的对象就会成为迭代器,提供迭代机制。
通过hasNext查找是否还有下一个元素,并在hasNext返回true时反复地调用next方法,获取下一个元素。
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
...
}
3. Iterable和Iterator关系
Iterable是一个对象拥有被迭代的“资格”,而Iterator是一个真正干事的迭代器。
3.1 发现问题
我们通过一个测试程序来对这两个接口进行说明。源码如下:
这是一个能够动态调整数组大小的栈。
/**
* Resizing array stack
* @author lastwhisper
*/
public class ResizingArrayStack<Item>{
private Item[] a;// stack entries
private int N;// size
// Create a empty stack of size cap.
public ResizingArrayStack(int cap) {
a = (Item[]) new Object[cap];
}
// Add a item.
public void push(Item item) {
if (N == a.length) {
resize(2 * a.length);
}
a[N++] = item;
}
// Delete recently added item.
public Item pop() {
Item item = a[--N];
a[N] = null;
if (N > 0 && N == a.length / 4) {
resize(a.length / 2);
}
return item;
}
// Is the stack empty?
public boolean isEmpty() {
return N == 0;
}
// The numebr of items int the stack
public int size() {
return N;
}
private void resize(int max) {
// Move the stack of size N<=max to a new array of size max.
Item[] temp = (Item[]) new Object[max];
for (int i = 0; i < temp.length; i++) {
temp[i] = a[i];
}
a = temp;
}
}
我们如何来遍历这个栈呢?通常我们会使用foreach遍历。
/**
* @author lastwhisper
*/
public class IterableAndIterator {
public static void main(String[] args) {
ResizingArrayStack<String> stack = new ResizingArrayStack<String>(100);
stack.push("1");
stack.push("2");
stack.push("3");
for (String s : stack) {
System.out.printf("%s ",s);
}
}
}
但是编译器却报错说,foreach不能应用ResizingArrayStack类上。

这是因为foreach只是一个语法糖,本质上使用的还是使用迭代器遍历的,ResizingArrayStack并没有实现Iterable接口,所以无法被迭代!
3.2 解决问题
将ResizingArrayStack实现Iterable接口,并提供对应实现的迭代器。
/**
* Resizing array stack
* @author lastwhisper
*/
public class ResizingArrayStack<Item> implements Iterable<Item> {
...
@Override
public Iterator<Item> iterator() {
return new ReverseArrayIterator();
}
private class ReverseArrayIterator implements Iterator<Item> {
private int i = N;
@Override
public boolean hasNext() {
return i > 0;
}
@Override
public Item next() {
return a[--i];
}
@Override
public void remove() {
}
}
}
此时就可以使用foreach遍历,也可以使用迭代遍历。
/**
* @author lastwhisper
*/
public class IterableAndIterator {
public static void main(String[] args) {
ResizingArrayStack<String> stack = new ResizingArrayStack<String>(100);
stack.push("1");
stack.push("2");
stack.push("3");
// foreach
for (String s : stack) {
System.out.printf("%s ",s);
}
// iterator
Iterator<String> iterator = stack.iterator();
while (iterator.hasNext()){
String temp = iterator.next();
System.out.printf("%s ",temp);
}
}
}
4. foreach遍历与iterator遍历
foreach只是一种语法糖,foreach遍历本质上就是使用iterator遍历。
在java文件编译为class文件之后语法糖就会被消除,露出它的本质。
将带有foreach遍历的class文件,进行反编译(我使用的是jad反编译工具)。
for (String s : stack) {
System.out.printf("%s ", s);
}
将class文件反编译后foreach遍历被翻译为iterator遍历
String s;
for (Iterator iterator = stack.iterator(); iterator.hasNext();
System.out.printf("%s ", new Object[]{s}))
s = (String) iterator.next();
或者这样(http://javare.cn)
Iterator var2 = stack.iterator();
while(var2.hasNext()) {
String s = (String)var2.next();
System.out.printf("%s ", new Object[]{s});
}
网友评论