Iterator 和 Iterable 差别和联系「建议收藏」

Iterator 和 Iterable 差别和联系

大家好,又见面了,我是全栈君。

用Iterator模式实现遍历集合 

        Iterator模式是用于遍历集合类的标准訪问方法。它能够把訪问逻辑从不同类型的集合类中抽象出来,从而避免向client暴露集合的内部结构。

        比如,假设没有使用Iterator,遍历一个数组的方法是使用索引: for(int i=0; i<array.size(); i++) { … get(i) … }

        而訪问一个链表(LinkedList)又必须使用while循环: while((e=e.next())!=null) { … e.data() … } 

        以上两种方法client都必须事先知道集合的内部结构,訪问代码和集合本身是紧耦合。无法将訪问逻辑从集合类和client代码中分离出来,每一种集合相应一种遍历方法,client代码无法复用。

        更恐怖的是,假设以后须要把ArrayList更换为LinkedList,则原来的client代码必须所有重写。

        解决以上问题。Iterator模式总是用同一种逻辑来遍历集合: for(Iterator it = c.iterater(); it.hasNext(); ) { … } 

        奥秘在于client自身不维护遍历集合的”指针”。全部的内部状态(如当前元素位置,是否有下一个元素)都由Iterator来维护,而这个Iterator由集合类通过工厂方法生成。因此,它知道怎样遍历整个集合。

 

        client从不直接和集合类打交道,它总是控制Iterator,向它发送”向前”,”向后”。”取当前元素”的命令,就能够间接遍历整个集合。 

        首先看看java.util.Iterator接口的定义:
                public interface Iterator { boolean hasNext(); Object next(); void remove(); } 

        依赖前两个方法就能完毕遍历,典型的代码例如以下:
                for(Iterator it = c.iterator(); it.hasNext(); ) { Object o = it.next(); // 对o的操作… } 

        每一种集合类返回的Iterator详细类型可能不同,Array可能返回ArrayIterator,Set可能返回 SetIterator。Tree可能返回TreeIterator,可是它们都实现了Iterator接口。因此,client不关心究竟是哪种 Iterator,它仅仅须要获得这个Iterator接口就可以。这就是面向对象的威力。 

        全部集合类都实现了 Collection 接口,而 Collection 继承了 Iterable 接口。

/**
 * Implementing this interface allows an object to be the target of
 * the "foreach" statement.
 *
 * @param <T> the type of elements returned by the iterator
 *
 * @since 1.5
 */
public interface Iterable<T> {

    /**
     * Returns an iterator over a set of elements of type T.
     *
     * @return an Iterator.
     */
    Iterator<T> iterator();
}

        而在详细的实现类中(比方 ArrayList),则在内部维护了一个 Itr 内部类。该类继承了 Iterator 接口,它的hasNext() 和 next() 方法是和 ArrayList 实现相耦合的。

当调用 ArrayList 对象的 iterator() 方法的时候,返回该类 Itr 的一个实例,从而实现遍历 ArrayList 的功能。

public Iterator<E> iterator() {
        return new Itr();
    }

    /**
     * An optimized version of AbstractList.Itr
     */
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

为什么一定要去实现Iterable这个接口呢?为什么不直接实现Iterator接口呢?

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

        由于Iterator接口的核心方法next()或者hasNext() 是依赖于迭代器的当前迭代位置的。

假设Collection直接实现Iterator接口。势必导致集合对象中包括当前迭代位置的数据(指针)。 当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。

除非再为Iterator接口加入一个reset()方法,用来重置当前迭代位置。 但即时这样,Collection也仅仅能同一时候存在一个当前迭代位置

而Iterable则不然,每次调用都会返回一个从头開始计数的迭代器。 多个迭代器是互不干扰的。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/116401.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • js判断是否是数字

    js判断是否是数字js判断是否是数字 (请输入数字)       functioncheckRate(input){    varre=/^[0-9]+.?[0-9]*$/;  //判断字符串是否为数字    //判断正整数/^[1-9]+[0-9]*]*$/    varnubmer=document.getElementById(input

  • ps批量磨皮滤镜插件ArcSoft Portrait3+ 中文版瘦脸自动识别人脸win/mac支持2018「建议收藏」

    ps批量磨皮滤镜插件ArcSoft Portrait3+ 中文版瘦脸自动识别人脸win/mac支持2018「建议收藏」【系统支持】win系统(win10系统PS不能使用插件版,但是可以使用独立版)mac苹果系统只能使用插件版,不能使用独立版【支持PS】支持CS6-CC2108也可以独立使用苹果系统不能独立使用ArcSoftPortrait+是一款智能化的人像磨皮软件,采用世界上最尖端的人脸检测技术,能够自动检测人像脸部进行磨皮。ArcSoftPortrait+还支持批量处理功能,能同时处理上千张…

  • 标准网页两侧浮动广告代码,支持FF及IE

    标准网页两侧浮动广告代码,支持FF及IE点击这里使用RSS订阅本Blog:网页两侧浮动广告代码经测试支持IE、Firefox等浏览器符合标准的正常工作的对联广告lastScrollY=0;functionheartBeat(){vardiffY;if(doc

  • SpringCloud之SpringCloud常见面试题, SOA和微服务关系, SpringCloud和Dubbo区别, Eureka和Zookeeper区别「建议收藏」

    SpringCloud之SpringCloud常见面试题, SOA和微服务关系, SpringCloud和Dubbo区别, Eureka和Zookeeper区别「建议收藏」1.SpringCloud是什么SpringCloud是一系列框架的集合,集成SpringBoot,提供很多优秀服务:服务发现和注册,统一配置中心,负载均衡,网关,熔断器等。2.SpringCloud的优势因为SpringCloud源于Spring,所以它的质量,稳定性,持续性都是可以保证的。SpringCloiud天热支持SpringBoot框架,就可以提高开发效率,能够实现需求。SpringCloud更新很快,后期支持很给力。SpringCloud可以用来开发微服务。3.Sp

  • pywin32、win32api、win32gui、win32com、win32con 都是啥?「建议收藏」

    pywin32、win32api、win32gui、win32com、win32con 都是啥?「建议收藏」pywin32、win32api、win32gui、win32com、win32con名称非常类似,特别容易混淆,今天就用600字给大家区分一下文章目录pywin32win32guiwin32conwin32apiwin32com记录时间pywin32pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个模块库。该模块的另一个作用是是通过Python进行COM编程。落地场景:如果你想在Windows操作系统用Python实现自动化工作,pywin32模块经常用到

    2022年10月11日
  • VS2019、VS2017、VS2013产品密钥

    VS2019、VS2017、VS2013产品密钥VisualStudio2013VisualStudioUltimate2013KEY:BWG7X-J98B3-W34RT-33B3R-JVYW9VisualStudioPremium2013KEY:FBJVC-3CMTX-D8DVP-RTQCT-92494VisualStudioProfessional2013KEY:XDM3T-W3T3V-MGJWK-8B…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号