zoukankan      html  css  js  c++  java
  • java学习--Iterable 和 Iterator

    Iterable 

    Iterable :故名思议,实现了这个接口的集合对象支持迭代,是可迭代的。

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

    Iterator

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

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


    default修饰符,这也是Java 8后新出现的,我们知道,如果我们给一个接口新添加一个方法,那么所有他的具体子类都必须实现此方法,

    为了能给接口拓展新功能,而又不必每个子类都要实现此方法,Java 8新加了default关键字,被其修饰的方法可以不必由子类实现,并且由dafault修饰的方法在接口中有方法体,这打破了Java之前对接口方法的规范.

     
     
     

     

    总结 :

    一个集合类要想可以迭代遍历,就必须实现Iterable接口,即必须重写Iterable接口的iterator()方法,而iterator()方法必须返回一个迭代器对象。

    迭代器对象就是实现了Iterator接口的迭代器类的实例,而迭代器类必须要重写Iterator接口的hasNext() 和 next() 方法,remove方法虽然default,最好根据需要重写

    实现Iterable接口的目的就是为了通过重写iterator()方法得到一个实现了Iterator接口的迭代器类的实例,为什么一定要实现Iterable接口,为什么不直接实现Iterator接口呢?

     看一下JDK中的集合类,比如List一族或者Set一族,都是实现了Iterable接口,但并不直接实现Iterator接口。 
    仔细想一下这么做是有道理的。 

          因为Iterator接口的核心方法next()或者hasNext() 是依赖于迭代器的当前迭代位置的。 
          如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代位置的数据(指针)。 
          当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。 
          除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。 
          但即时这样,Collection也只能同时存在一个当前迭代位置。 
          而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。 
          多个迭代器是互不干扰的。 

    迭代器的使用实例

    下面是手动迭代的例子,

    foreach内部原理其实就是如下实现的(如果要在迭代中删除元素,只能使用手动迭代,不能使用foreach,因为foreach无法调用迭代器的remove方法

    public static void main(String[] args)
    {
            List<Integer> li = new ArrayList<>();        
            li.add(1);
            li.add(2);
            li.add(3);
            
            //不使用foreach 而手动迭代
            Iterator<Integer> iter = li.iterator();    //获取ArrayList 的迭代器
            while(iter.hasNext())                      //①先探测能否继续迭代
            {
                System.out.println(iter.next());       //②后取出本次迭代出的元素
                //invoke  iter.remove()                     //③最后如果需要,调用remove              
            }      
    }

      

    迭代器类的实现实例

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

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

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

    private class Itr implements Iterator<E> 
    {
           /*
                   AbstractList 中实现的迭代器,删除了一些细节。不影响理解
                   Itr为一个priavate成员内部类
           
           */     
            int cursor = 0;   //马上等待被迭代元素的index
    
            //最近一次,已经被迭代出的元素的index,如果这个元素迭代后,被删除了,则lastRet重置为-1
            int lastRet = -1;
    
            public boolean hasNext() {
                return cursor != size();      //当前游标值 等于  集合的size()  说明已经不能再迭代了。
            }
    
            public E next() {
                    int i = cursor;
                    E next = get(i);
                    lastRet = i;     //lastRet 保存的是最近一次已经被迭代出去的元素索引
                    cursor = i + 1;  //cursor为马上等待被迭代的元素的索引
                    return next;
            }
    
            public void remove()
            {
                if (lastRet < 0)                             //调用remove之前没有调用next
                    throw new IllegalStateException();       //则抛异常。这就是为什么在使用remove前,要next的原因
    
                OuterList.this.remove(lastRet);            //从集合中删除这个元素
    
                if (lastRet < cursor)                      //集合删除元素后,集合后面的元素的索引会都减小1,cursor也要同步后移
                    cursor--;
    
                lastRet = -1;                                 //重置          
            }
    }
  • 相关阅读:
    天梯程序设计竞赛 L2-005. 集合相似度 STL
    Oulipo kmp
    剪花布条 kmp
    poj 1321 dfs
    蓝桥杯历届试题 打印十字图
    windows 10家庭版安装SQL Server 2014出现.net 3.5失败问题解决。
    使用分区助手转移windows 10系统出现黑屏boot manager报错问题。
    使用java AWT做一个增加按钮的简单菜单窗体
    R基本画图
    R的基础学习之数据结构
  • 原文地址:https://www.cnblogs.com/gaoBlog/p/10769696.html
Copyright © 2011-2022 走看看