java 迭代_Java迭代 : Iterator和Iterable接口

从英文意思去理解

Iterable :故名思议,实现了这个接口的集合对象支持迭代,是可迭代的。able结尾的表示 能...样,可以做...。

Iterator:   在英语中or 结尾是都是表示 ...样的人 or ... 者。如creator就是创作者的意思。这里也是一样:iterator就是迭代者,我们一般叫迭代器,它就是提供迭代机制的对象,具体如何迭代,都是Iterator接口规范的。

Iterable

一个集合对象要表明自己支持迭代,能有使用foreach语句的特权,就必须实现Iterable接口,表明我是可迭代的!然而实现Iterable接口,就必需为foreach语句提供一个迭代器。

这个迭代器是用接口定义的 iterator方法提供的。也就是iterator方法需要返回一个Iterator对象。

foreach只能用于数组和实现了Iterable接口的类

//Iterable JDK源码

//可以通过成员内部类,方法内部类,甚至匿名内部类去实现Iterator

public interface Iterable{

Iteratoriterator();

}

Iterator

包含3个方法: hasNext ,  next , remove。remove按需求实现,一般它很少用到,以至于Eclipse接口方法自动补全时,都忽略了remove放方法。

1、每次在迭代前   ,先调用hasNext()探测是否迭代到终点(本次还能再迭代吗?)。

2、next方法不仅要返回当前元素,还要后移游标cursor

3、remove()方法用来删除最近一次已经迭代出的元素

4、 迭代出的元素是原集合中元素的拷贝(重要)

5、配合foreach使用

//Iterator接口的JDK源码,注释为整理建议使用Iterator的正确姿势

public interface Iterator{boolean hasNext(); //每次next之前,先调用此方法探测是否迭代到终点

E next();//返回当前迭代元素 ,同时,迭代游标后移

/*删除最近一次已近迭代出出去的那个元素。

只有当next执行完后,才能调用remove函数。

比如你要删除第一个元素,不能直接调用 remove() 而要先next一下( );

在没有先调用next 就调用remove方法是会抛出异常的。

这个和MySQL中的ResultSet很类似*/

voidremove()

{throw new UnsupportedOperationException("remove");

}

}

迭代的具体细节

需要理解的地方

1、hasNext , next  , remove 的调用顺序

2、迭代出来的是原集合元素拷贝!

下面是手动迭代的例子,foreach的原理和它一样。

public static voidmain(String[] args)

{

List li = new ArrayList<>();

li.add(1);

li.add(2);

li.add(3);

//不使用foreach 而手动迭代

Iterator iter = li.iterator(); //获取ArrayList 的迭代器

while(iter.hasNext()) //①先探测能否继续迭代

{

System.out.println(iter.next());//②后取出本次迭代出的元素//invoke remove() //③最后如果需要,调用remove

}}

AbstractList中实现的迭代器类,可以借鉴参考。

我们实现自己的迭代器的情况很少,毕竟JDK集合足够强大。

源码中有一些保护机制,为了便于理解我删改了。

private class Itr implements Iterator{

/*

AbstractList 中实现的迭代器,删除了一些细节。不影响理解 Itr为一个priavate成员内部类

*/int cursor = 0; //马上等待被迭代元素的index//最近一次,已经被迭代出的元素的index,如果这个元素迭代后,被删除了,则lastRet重置为-1

int lastRet = -1;public booleanhasNext() {return cursor !=size(); //当前游标值 等于 集合的size() 说明已经不能再迭代了。

}publicE next() {int i =cursor;

E next=get(i);

lastRet= i; //lastRet 保存的是最近一次已经被迭代出去的元素索引

cursor = i + 1; //cursor为马上等待被迭代的元素的索引

returnnext;

}public voidremove()

{if (lastRet < 0) //调用remove之前没有调用next

throw new IllegalStateException(); //则抛异常。这就是为什么在使用remove前,要next的原因

OuterList.this.remove(lastRet); //从集合中删除这个元素

if (lastRet < cursor) //集合删除元素后,集合后面的元素的索引会都减小1,cursor也要同步后移 cursor--;

lastRet= -1; //重置

}

}

迭代出来的元素都是原来集合元素的拷贝

Java集合中保存的元素实质是对象的引用(可以理解为C中的指针),而非对象本身。

迭代出的元素也就都是 引用的拷贝,结果还是引用。那么,如果集合中保存的元素是可变类型的,我们就可以通过迭代出的元素修改原集合中的对象。

而对于不可变类型,如String  基本元素的包装类型Integer 都是则不会反应到原集合中。

为了便于理解,画张图:

5a071b437f343cf2313699ccb0ae255e.png

验证代码:

public classMain

{public static voidmain(String[] args)

{

List li = new ArrayList<>();

Person p= new Person("Tom");

li.add(p);for(Person ap: li)

{

ap.setName("Jerry");

}

System.out.println(li.get(0).getName()); //Jerry not Tom

}

}classPerson

{publicPerson(String name)

{this.name = (name==null?"":name);

}privateString name;publicString getName()

{returnname;

}public voidsetName(String name)

{if(name == null)

name= "";this.name =name;

}

}

小试牛刀,让自己的类支持迭代。

public classMain

{public static voidmain(String[] args)

{

MyString s= new MyString("1234567");for(charc:s)

{

System.out.println(c);

}

}

}class MyString implements Iterable{private int length = 0;private String ineers = null;publicMyString(String s)

{this.ineers =s;this.length =s.length();

}

@Overridepublic Iteratoriterator()

{class iter implements Iterator //方法内部类

{private int cur= 0;

@Overridepublic booleanhasNext()

{return cur !=length;

}

@OverridepublicCharacter next()

{

Character c=ineers.charAt(cur);

cur++;returnc;

}public voidremove()

{//do nothing

}

}return new iter(); //安装Iterable接口的约定,返回迭代器

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值