黑马程序员技术交流社区
标题:
增强for循环中,集合变量可以是数组或者实现iterable接口的结合类
[打印本页]
作者:
李蛟龙
时间:
2012-4-25 23:22
标题:
增强for循环中,集合变量可以是数组或者实现iterable接口的结合类
为什么一定要去实现Iterable这个接口呢?为什么不直接实现Iterator接口呢?
作者:
小鹿叙鹿
时间:
2012-4-25 23:29
看一下JDK中的集合类,比如List一族或者Set一族,
都是实现了Iterable接口,但并不直接实现Iterator接口。
仔细想一下这么做是有道理的。因为Iterator接口的核心方法next()或者hasNext()
是依赖于迭代器的当前迭代位置的。
如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代位置的数据(指针)。
当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。
除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。
但即时这样,Collection也只能同时存在一个当前迭代位置。
而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。
多个迭代器是互不干扰的。
作者:
徐鑫
时间:
2012-4-25 23:47
Iterable接口实现后的功能是“返回”一个迭代器
而Iterator接口实现后的功能是“使用”一个迭代器
如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代位置的数据(指针)。
当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。
也就是说如果直接实现Iterator可能导致指针错误,而实现Iterable的话,每次都是使用新的迭代器,这样就不会出错
作者:
王勃
时间:
2012-4-26 00:08
我来补充一些,
Iterator接口是用于遍历Collection的实现类的标准访问方法。其中定义了三个方法:
-----boolean hasNext():如果别迭代的集合元素还没有被遍历,那么返回true。
-----Object next():返回集合里下一个元素。
-----void remove():删除集合里上一次next方法返回的元素。
注:Iterator本身不提供盛装对象的能力。如果需要创建Interator对象,则必须要有一个被迭代的集合。可以说他没集合引用,就无从谈起迭代集合元素,正是这一点限制了他。
访问代码和集合本身是紧耦合,无法将访问逻辑从集合类和客户端代码中分离出来,每一种集合对应一种遍历方法,客户端代码无法复用。更恐怖的是,如果以后需要把ArrayList更换为LinkedList,
则原来的客户端代码必须全部重写。也就是说从软件耦合度上分析,他对集合产生了严重依赖,这种设计模式很不ok,你知道为什么大家都喜欢用Spring3.0框架来做javaEE的中间层吗?
是的,就是Spring3.0的设计很好,对表现层和持久层的解耦工作做的十分到家。
那么现在Iterable接口就是他的改良。。降低的代码耦合度,是编程效率大大提高。。
作者:
王勃
时间:
2012-4-26 00:21
做了个例子看下吧。
package com.heima;
import java.lang.reflect.Field;
import java.util.Iterator;
public class Teacher 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 MyInterator();
}
public static void main(String[] args) {
Teacher t = new Teacher();
t.setName("hello heima!");
t.setAge(23);
for (Object o : t) {
System.out.println(o.toString());
}
}
private class MyInterator implements Iterator{
// 属性的索引
private int cursor=0;
// 属性的数组
private Field[] fields = Teacher.class.getDeclaredFields();
public boolean hasNext() {
return cursor!=(Teacher.class.getDeclaredFields().length);
}
public Object next() {
Object o=null;
try{
// 让内部类可以访问外部类的私有属性的值
fields[cursor].setAccessible(true);
o = fields[cursor].getName()+" "+fields[cursor].get(Teacher.this);
cursor++;
}catch(Exception e){
System.out.println(e);
}
return o;
}
public void remove() {
}
}
}
复制代码
作者:
王勃
时间:
2012-4-26 00:30
本帖最后由 王明(1988) 于 2012-4-26 00:43 编辑
JAVA中得各种集合实际上都对Iterator接口的3个方法重新覆盖了,而如果要使用foreach方法(增强的for循环)来遍历,那么就必须实现Iterable接口,一般实现方式就如上。
这一点很重要,如果你用实现Iterator接口的话,你的代码会和for循环(或者增强for,while循环)严重的耦合,直接造成,将来你的代码复用性特别差劲。
而我只需要自定义一个自己的迭代器类,在这个类采取继承Iterable接口,仔细看一下我的MyIterator类,是不是解耦工作做的不错!就非常的低耦合。是吧,以后修改,就爽多了。
其实在使用上,我觉得既然java集合大部分都实现了Iterable接口,那么必定是因为他的这个解耦优点,因为这种低耦合度的设计模式,写代码非常爽,
等你用过Spring3.0动态注入bean对象,配置xml文件时,你就明白为什么,要这么用他了。。。。
作者:
王勃
时间:
2012-4-26 00:49
本帖最后由 王明(1988) 于 2012-4-26 01:11 编辑
楼上2位说的,当使用Iterator时 ,当集合引用发生传递时,容易丢失迭代集合元素的指针,我想空指针异常不是java的风格吧(那是C++程序员的错误专利),所以java避免出现空指针,
那我们就果断实现Iterable接口吧。
再啰嗦一句:如果想用foreach(增强for)遍历自定义的集合,自定义类通常需要实现Iterable接口。(此句话,是我在java一本参考书上看到的,搬给你)
作者:
王勃
时间:
2012-4-26 01:13
刚看了一个贴子,说foreach的。。
ArrayList al=new ArrayList();
al.add("测试用1");
al.add("测试用2");
for (Object object : al) {
System.out.println(object);
}
那么到底为什么可以这样操作呢?
是因为JDK1.5 引入了新的呗称为Iterable的接口, 这个接口能产生一个Iteraror和Iterator()的方法 并且Iterable接口被foreach用来在序列中移动 因此如果你创建任何实现iterable的类都可以将它用于foreach语句中。
因为java集合们大都实现了Iterable接口的缘故。{:soso_e128:}这里表现的就非常解耦啊。。
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2