Java迭代 : Iterator和Iterable接口

从英文意思去理解

Iterable :故名思议,实现了这个接口的集合对象支持迭代,是可迭代的。able结尾的表示 能...样,可以做...。
Iterator:   在英语中or 结尾是都是表示 ...样的人 or ... 者。如creator就是创作者的意思。这里也是一样:iterator就是迭代者,我们一般叫迭代器,它就是提供迭代机制的对象,具体如何迭代,都是Iterator接口规范的。
 
 
 

Iterable

一个集合对象要表明自己支持迭代,能有使用foreach语句的特权,就必须实现Iterable接口,表明我是可迭代的!然而实现Iterable接口,就必需为foreach语句提供一个迭代器。
这个迭代器是用接口定义的 iterator方法提供的。也就是iterator方法需要返回一个Iterator对象。
  1. //Iterable JDK源码
    //可以通过成员内部类,方法内部类,甚至匿名内部类去实现Iterator
  2.  
  3. public interface Iterable<T>
  4. {
  5.  
  6. Iterator<T> iterator();
  7. }

Iterator

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

1、每次在迭代前   ,先调用hasNext()探测是否迭代到终点(本次还能再迭代吗?)。
2、next方法不仅要返回当前元素,还要后移游标cursor
3、remove()方法用来删除最近一次已经迭代出的元素
4、 迭代出的元素是原集合中元素的拷贝(重要)
5、配合foreach使用
  1. //Iterator接口的JDK源码,注释为整理建议使用Iterator的正确姿势
  2.  
  3. public interface Iterator<E> {
  4.  
  5. boolean hasNext(); //每次next之前,先调用此方法探测是否迭代到终点
  6.  
  7. E next(); //返回当前迭代元素 ,同时,迭代游标后移
  8.  
  9. /*删除最近一次已近迭代出出去的那个元素。
  10. 只有当next执行完后,才能调用remove函数。
  11. 比如你要删除第一个元素,不能直接调用 remove() 而要先next一下( );
  12. 在没有先调用next 就调用remove方法是会抛出异常的。
  13. 这个和MySQL中的ResultSet很类似
  14. */
  15. void remove()
    {
  16. throw new UnsupportedOperationException("remove");
  17. }
  18. }

迭代的具体细节

需要理解的地方

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

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

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

  1. public static void main(String[] args)
  2. {
  3.  
  4. List<Integer> li = new ArrayList<>();
  5.  
  6. li.add(1);
  7. li.add(2);
  8. li.add(3);

  9. //不使用foreach 而手动迭代
  10. Iterator<Integer> iter = li.iterator(); //获取ArrayList 的迭代器
  11.  
  12. while(iter.hasNext()) //①先探测能否继续迭代
  13. {
  14. System.out.println(iter.next()); //②后取出本次迭代出的元素
  15.  
  16. //invoke remove() //③最后如果需要,调用remove
  17.  
  18. }
  19.  
  20. }

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

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

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

  1. private class Itr implements Iterator<E>
    {
  2. /*
    AbstractList 中实现的迭代器,删除了一些细节。不影响理解
    Itr为一个priavate成员内部类
  3.  
  4. */
  5.  
  6. int cursor = 0; //马上等待被迭代元素的index
  7.  
  8. //最近一次,已经被迭代出的元素的index,如果这个元素迭代后,被删除了,则lastRet重置为-1
  9.  
  10. int lastRet = -1;
  11.  
  12. public boolean hasNext() {
  13. return cursor != size(); //当前游标值 等于 集合的size() 说明已经不能再迭代了。
  14. }
  15.  
  16. public E next() {
  17.  
  18. int i = cursor;
  19. E next = get(i);
  20. lastRet = i; //lastRet 保存的是最近一次已经被迭代出去的元素索引
  21. cursor = i + 1; //cursor为马上等待被迭代的元素的索引
  22. return next;
  23.  
  24. }
  25.  
  26. public void remove()
  27. {
  28.  
  29. if (lastRet < 0) //调用remove之前没有调用next
  30. throw new IllegalStateException(); //则抛异常。这就是为什么在使用remove前,要next的原因
  31.  
  32. OuterList.this.remove(lastRet); //从集合中删除这个元素
  33.  
  34. if (lastRet < cursor) //集合删除元素后,集合后面的元素的索引会都减小1,cursor也要同步后移
  35. cursor--;
  36.  
  37. lastRet = -1; //重置
  38.  
  39. }
  40.  
  41. }

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

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

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

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

为了便于理解,画张图:

验证代码:

  1. public class Main
  2. {
  3.  
  4. public static void main(String[] args)
  5. {
  6.  
  7. List<Person> li = new ArrayList<>();
  8.  
  9. Person p = new Person("Tom");
  10.  
  11. li.add(p);
  12.  
  13. for(Person ap: li)
  14. {
  15. ap.setName("Jerry");
  16. }
  17.  
  18. System.out.println(li.get(0).getName()); //Jerry not Tom
  19.  
  20. }
  21.  
  22. }
  23.  
  24. class Person
  25. {
  26.  
  27. public Person(String name)
  28. {
  29. this.name = (name==null?"":name);
  30.  
  31. }
  32.  
  33. private String name;
  34.  
  35. public String getName()
  36. {
  37. return name;
  38. }
  39.  
  40. public void setName(String name)
  41. {
  42. if(name == null)
  43. name = "";
  44. this.name = name;
  45. }
  46.  
  47. }

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

  1. public class Main
  2. {
  3.  
  4. public static void main(String[] args)
  5. {
  6.  
  7. MyString s = new MyString("1234567");
  8.  
  9. for(char c:s)
  10. {
  11. System.out.println(c);
  12. }
  13.  
  14. }
  15.  
  16. }
  17.  
  18. class MyString implements Iterable<Character>
  19. {
  20.  
  21. private int length = 0;
  22. private String ineers = null;
  23.  
  24. public MyString(String s)
  25. {
  26. this.ineers = s;
  27. this.length = s.length();
  28.  
  29. }
  30.  
  31. @Override
  32. public Iterator<Character> iterator()
  33. {
  34.  
  35. class iter implements Iterator<Character> //方法内部类
  36. {
  37. private int cur= 0;
  38.  
  39. @Override
  40. public boolean hasNext()
  41. {
  42. return cur != length;
  43. }
  44.  
  45. @Override
  46. public Character next()
  47. {
  48.  
  49. Character c = ineers.charAt(cur);
  50. cur++;
  51. return c;
  52. }
  53.  
  54. public void remove()
  55. {
  56. // do nothing
  57.  
  58. }
  59.  
  60. }
  61. return new iter(); //安装Iterable接口的约定,返回迭代器
  62.  
  63. }
  64.  
  65. }

【转】Java迭代:Iterator和Iterable接口的更多相关文章

  1. Java迭代 : Iterator和Iterable接口

    从英文意思去理解 Iterable :故名思议,实现了这个接口的集合对象支持迭代,是可迭代的.able结尾的表示 能...样,可以做.... Iterator:   在英语中or 结尾是都是表示 .. ...

  2. Iterator、Iterable接口的使用及详解

    Java集合类库将集合的接口与实现分离.同样的接口,可以有不同的实现. Java集合类的基本接口是Collection接口.而Collection接口必须实现Iterator接口. 以下图表示集合框架 ...

  3. java 集合框架(二)Iterable接口

    Iterable接口是java 集合框架的顶级接口,实现此接口使集合对象可以通过迭代器遍历自身元素,我们可以看下它的成员方法 修饰符和返回值 方法名 描述 Iterator<T> iter ...

  4. Java 迭代接口:Iterator、ListIterator 和 Spliterator

    1. 简介 当我们使用 for 或 while 循环来遍历一个集合的元素,Iterator 允许我们不用担心索引位置,甚至让我们不仅仅是遍历一个集合,同时还可以改变它.例如,你如果要删除循环中的元素, ...

  5. java集合-Iterator迭代

    我们常常使用 JDK 提供的迭代接口进行 Java 集合的迭代. Iterator iterator = list.iterator(); while(iterator.hasNext()){ Str ...

  6. Java中Iterator类的详细介绍

    迭代器模式:就是提供一种方法对一个容器对象中的各个元素进行访问,而又不暴露该对象容器的内部细节. 概述 Java集合框架的集合类,我们有时候称之为容器.容器的种类有很多种,比如ArrayList.Li ...

  7. iterator和iterable的区别

    相关博客:  http://blog.csdn.net/lipengcn/article/details/51700153         Java中Iterable和Iterator的辨析 http ...

  8. Java之iterator迭代器和iterable接口

    java.lang.Iterable java.util.Iterator Iterator是迭代器类,而Iterable是接口. 好多类都实现了Iterable接口,这样对象就可以调用iterato ...

  9. java中的Iterator和Iterable 区别

    java.lang.Iterable java.util.Iterator 来自百度知道: Iterator是迭代器类,而Iterable是接口. 好多类都实现了Iterable接口,这样对象就可以调 ...

随机推荐

  1. Android接入微信SDK之一:发起微信授权登录

    1.重要的事情首先说! 包名.应用签名.app id 三者都必须和在腾讯上申请的一致!!!否则将不能成功. 包名:就是在腾讯上申请的包名 应用签名:使用微信官网提供的<签名生成工具>(这个 ...

  2. 不会 tsconfig | tslint 常遇到的问题

    1. require('xx-xx') 不能用时 https://stackoverflow.com/questions/31173738/typescript-getting-error-ts230 ...

  3. array_map的使用

    其结果为:

  4. Python 编程快速上手 第六章总结

    第六章 字符串操作 前言 这一章节讲了关于 Python 中字符串类型的知识.与字符串有关的操作符,方法等等. 处理字符串:字符串的写入.打印.访问的知识 原始字符串 格式:r'string'作用:在 ...

  5. Sparksql的内置函数的使用以及案例

    开发环境:spark:2.2.0 工具:IDEA OS:Windows 数据文件: 001E8CB5AB11,ASUSTek,2018-07-12 14:00:57,2018-07-12 14:00: ...

  6. No address associated with hostname

    java.net.UnknownHostException: Unable to resolve host "www.baidu.com": No address associat ...

  7. 小程序授权demo

    <button wx:if="{{canIUse}}"   open-type="getUserInfo"  bindgetuserinfo=" ...

  8. PHP如何定义类及其成员属性与操作

    1.类的定义: 类的关键字定义使用class 1.定义一个空类 Class Person{}; 2.定义一个有成员属性和操作的类 Class Person{ //成员属性 $name     =  ' ...

  9. php字段转义

    addslashes() 函数返回在预定义的字符前添加反斜杠的字符串. 预定义字符是:在以下符号前加/ 单引号(') 双引号(") 反斜杠(\) NULL parse_str($str,$a ...

  10. mysql知识点总结

    一.mysql_connect(),在php7已移除,有mysqli_connect(),pdo,代替. <?php header("Content-type:text/html;ch ...