iterable接口最重要的方法是
Iterator<T> iterator();
//返回一个迭代器Iterator,而Iterator也是一个接口所以有很大的自由,
Iterator接口最重要的方法是:以前三个最重要对任何一个集合实例都可以用这三个方法进行遍历所有元素。
Iterator接口是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。
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());
}
}
用这两个集合有什么好处呢?在我们没有这两个集合之前我们是怎么对容器类实例元素遍历的呢?
如果没有使用Iterator,遍历一个数组的方法是使用索引:
for(int i=0; i<array.size(); i++) { ... get(i) ... }
//而访问一个链表(LinkedList)又必须使用while循环:
while((e=e.next())!=null) { ... e.data() ... }
以上两种方法客户端程序员都必须事先知道集合的内部结构,访问代码和集合本身是紧耦合,无法将访问逻辑从集合类和客户端代码中分离出来,每一种集合对应一种遍历方法,客户端代码无法复用。
更恐怖的是,如果需要把ArrayList更换为LinkedList,则原来的客户端代码必须全部重写。而限制有了这个接口后呢,每种集合类自己在内部实现这个Iterator接口的子类,然后集合类通过实现iterable接口返回这个Iterator接口子类的实例。这样呢通过Iterator接口可以让每 一种集合类返回的Iterator具体类型可能不同,Array可能返回ArrayIterator,Set可能返回SetIterator,Tree可 能返回TreeIterator,但是它们都实现了Iterator接口,因此,客户端不关心到底是哪种Iterator,它只需要获得这个 Iterator接口即可,这就是面向对象的威力。
在JDK1.5中,还对上面的遍历代码在语法上作了简化(但是限于只读,如果需要remove,还是直接使用iterator):使用foreach语句,想用foreach遍历自定义类的集合,自定义类通常需要实现implement iterable接口
// Type是具体的类型,如String。 for(Type t : c) { // 对t的操作… }
比如下面这个示例:自定义类实现了iterable接口实现了iterator()方法,这个自定义的iterator类就是将我自定义的的IteratorDemo的所有属性以键值对形式输出。
package server.socket;
import java.lang.reflect.Field;
import java.util.Iterator;
//public class IteratorDemo {
//
//}
public class IteratorDemo implements Iterable{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Iterator iterator() {
return new Itr();
}
public static void main(String[] args) {
IteratorDemo t = new IteratorDemo();
t.setName("aaaaaaa");
t.setAge(23);
for (Object o : t) {
System.out.println(o.toString());
}
}
/**
* 这个iterator用于遍历实例的所有属性以及属性的值
* @author vincent
*
*/
private class Itr implements Iterator{
private int cursor=0; // 属性的索引
private Field[] fields = IteratorDemo.class.getDeclaredFields(); // 获取所有属性的数组
public boolean hasNext() {
return cursor!=(IteratorDemo.class.getDeclaredFields().length);
}
public Object next() {
Object o=null;
try{
fields[cursor].setAccessible(true); // 让内部类可以访问外部类的私有属性的值
o = fields[cursor].getName()+" "+fields[cursor].get(IteratorDemo.this);
//fields[cursor].getName()获取属性的名字
//fields[cursor].get(IteratorDemo.this)获取实例该属性对于的值
cursor++;
}catch(Exception e){
System.out.println(e);
}
return o;
}
public void remove() {
// TODO Auto-generated method stub
}
}
}
输出结果:
为什么一定要去实现Iterable这个接口呢? 为什么不直接实现Iterator接口呢?
看一下JDK中的集合类,比如List一族或者Set一族,
都是实现了Iterable接口,但并不直接实现Iterator接口,而是通过内部类实现呢。
我觉得是这样,因为Iterator接口的核心方法next()或者hasNext()是依赖于迭代器的具体迭代集合来的。
如果Collection直接实现Iterator接口,势必导致集合子类ArrayList,LinkedList,hashset对象中包含以前Collection接口的一样的数据结构,而现实是ArrayList是基于数组,LinkedList是基于链表的两种完全不一样的数据结构。所有具体迭代器实例是各自集合类内部实现Iterator接口来实现。并通过集合类实现iterable接口来想外提供这个接口。
参考文献