【IT168 技术文档】1.迭代器Iterator
迭代器是一个对象,它的工作是遍历并选择序列中的对象。客户端程序员不关心序列底层的结构。此外,迭代器通常被称为“轻量级”对象:创建它的代价小。因此,经常可以见到对迭代器有些奇怪的限制。
Java 的Iterator 就是迭代器受限制的例子,它只能用来:
1)使用方法 iterator()要求容器返回一个 Iterator。第一次调用Iterator 的next()方法时,它返回序列的第一个元素。
2)使用next()获得序列中的下一个元素。
3)使用hasNext()检查序列中是否还有元素。
4)使用remove()将上一次返回的元素从迭代器中移除。
import java.util.ArrayList; import java.util.Iterator; import java.util.List; class Cat { private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } Cat(int i) { id = i; } } public class Cats { public static void main(String[] args) { List cats = new ArrayList(); for (int i = 0; i < 7; i++) cats.add(new Cat(i)); System.out.println("before remove:"+cats.size()); Iterator e = cats.iterator(); while (e.hasNext()) { //e.remove();//java.lang.IllegalStateException System.out.println("Cat id:" + ((Cat) e.next()).getId()); e.remove(); } System.out.println("after remove:"+cats.size()); } }
结果:
before remove:7
Cat id:0
Cat id:1
Cat id:2
Cat id:3
Cat id:4
Cat id:5
Cat id:6
after remove:0
这里必须注意remove()方法的使用,在调用该方法之前必须先调用next()方法。
2.迭代器ListIterator
该迭代器只能用于各种List类的访问。ListIterator可以双向移动。
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.ListIterator; public class ListIteration { public static void main(String[] args) { List stringList = new ArrayList(Arrays.asList("a", "b", "c", "d", "e")); ListIterator it = stringList.listIterator(); while (it.hasNext()) System.out.print(it.next() + "," + it.nextIndex() + "," + it.previousIndex() + ";"); System.out.println(); //回溯 while(it.hasPrevious()) System.out.print(it.previous()+" "); System.out.println(); System.out.println(stringList); it=stringList.listIterator(2); while(it.hasNext()){ it.next(); it.set("z"); } System.out.println(stringList); } }
结果:
a,1,0;b,2,1;c,3,2;d,4,3;e,5,4;
e d c b a
[a, b, c, d, e]
[a, b, z, z, z]
①next()得到下一个元素;previous()得到前一个元素。
②nextIndex()得到下一个元素的索引号;previousIndex()得到前一个元素的索引号。
③hasNext()判断是否还有后继元素;hasPrevious()判断是否还有前驱元素。
④listIterator()得到该集合的迭代器;listIterator(n)得到一个子迭代器,从原集合中第n+1个元素起(注意考虑第一个元素索引号为0)至集合末尾的所有元素组成一个子迭代器。
⑤set(“newElement”)将当前元素替换为newElement。这个方法的调用类似remove()方法,需要先调用next()方法。
3.Iterable接口与Foreach
Iterable接口包含一个能够产生Iterator的iterator()方法,并且Iterable接口被foreach用来在序列中移动。因此如果创建了任何实现Iterable接口的类,都可以将它用于foreach语句中。
import java.util.Iterator; public class IterableClass implements Iterable { protected String[] words = ("And that is how " + "we know the Earth to be banana-shaped.").split(" "); public Iterator iterator() { return new Iterator() { private int index = 0; public boolean hasNext() { return index < words.length; } public String next() { return words[index++]; } public void remove() {} }; } public static void main(String[] args){ for(String s:new IterableClass()) System.out.print(s+","); } }
结果:
And,that,is,how,we,know,the,Earth,to,be,banana-shaped.,
这个例子中,IterableClass类实现了Iterable接口,该接口只有一个方法:
Iterator
使用内部类实现这个Iterator接口,该接口有三个方法:
boolean hasNext();
E next();
void remove();
但是,如果尝试把数组当作一个Iterable参数传递会导致失败。这说明不存在任何从数组到Iterable的自动转换。
import java.util.Arrays; public class ArrayIsNotIterable { static void test(Iterable ib){ for(T t:ib) System.out.print(t+" "); } public static void main(String[] args){ test(Arrays.asList(1,2,3)); String[] strs={"A","B","C"}; //test(strs);ERROR test(Arrays.asList(strs)); } }
4.实现特定功能的Foreach
前面已经讨论了,foreach语法是通过Iterable接口实现移动的,所以如果需要改变foreach语句的逻辑功能,其实质就是覆盖底层Iterable中Iterator接口中三个方法的逻辑实现。下面,我们实现反向的Foreach“效果”。
import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; @SuppressWarnings("serial") class ReversibleArrayList extends ArrayList { public ReversibleArrayList(Collection c) { super(c); } public Iterable reversed() { return new Iterable() { public Iterator iterator() { return new Iterator() { int current = size() - 1; public boolean hasNext() { return current > -1; } public T next() { return get(current--); } public void remove() { } }; } }; } } public class AdapterMethodIdiom { public static void main(String[] args) { ReversibleArrayList ral = new ReversibleArrayList( Arrays.asList("To be or not to be".split(" "))); for (String s : ral) System.out.print(s + " "); System.out.println(); for (String s : ral.reversed()) System.out.print(s + " "); } }
结果:
To be or not to be
be to not or be To
在这个例子中,ReversibleArrayList类又实现了一个Iterable接口,名为reversed(),将其底层Iterator接口中的三个方法的逻辑实现为反向的遍历,就达到了反向Foreach的效果。从这个示例中,我们还可以注意到:
ReversibleArrayList ral = new ReversibleArrayList(…); for (String s : ral) //此处的ral其实是Iterable接口的引用,因为ReversibleArrayList类是实现Iterable接口的。