zoukankan      html  css  js  c++  java
  • Java容器源码攻坚战--第一战:Iterator

    基于java10.1

    零、前言

    如果想读读源码测试功力,或读读源码修养身心,或读读源码满足自虐倾向,我建议第一个类是:ArrayList
    第一、常用----所以用法比较熟悉,看完源码你也会更明白如何去用
    第二、相对简单----1595行代码,刨去注释的一大堆也没有太多,还是hold的住的
    第三、还没想好

    这篇并不是讲ArrayList,而是Iterator,它是容器以及映射中非常重要的一环

    一、迭代器模式

    提起设计模式,总是有种只知其形,难达其意的感觉,用三个字说就是高大上

    迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
    
    优势:  它支持以不同的方式遍历一个聚合
            迭代器简化了聚合的接口
            在同一个聚合上可以有多个遍历
    
    9414344-03ce729ea0176c36.png
    迭代器模式.png
    1.适配器接口

    最简单的适配器有两个方法hasNext()和next(),这两个方法可以组成一个逻辑链:如果有下一个,取出下一个

    /**
     * 作者:张风捷特烈
     * 时间:2018/10/1 0001:23:11
     * 邮箱:1981462002@qq.com
     * 说明:适配器接口
     */
    public interface Iterator<T> {
        /**
         * 是否有下一个元素
         * @return 是否有下一个元素
         */
        boolean hasNext();
    
        /**
         * 下一个元素
         * @return 下一个元素
         */
        T next();
    }
    
    2.聚合对象接口

    所谓聚合就是内部含有多个某类型的元素,比如教室和学生的关系,就是聚合对象(教室)与单体元素(学生)的关系

    /**
     * 作者:张风捷特烈
     * 时间:2018/10/1 0001:23:17
     * 邮箱:1981462002@qq.com
     * 说明:聚合对象接口
     */
    public interface Group<T> {
        /**
         * 添加元素
         * @param el 元素
         */
        void add(T el);
    
        /**
         * 获取元素
         * @param index 索引
         * @return 元素
         */ 
        T get(int index);
    
        /**
         * 获取迭代器
         * @return 迭代器
         */
        Iterator<T> iterator();
    
        /**
         * 内部元素总数
         * @return 元素总数
         */
        int size();
    }
    
    3.迭代器实现类
    /**
     * 作者:张风捷特烈
     * 时间:2018/10/1 0001:23:13
     * 邮箱:1981462002@qq.com
     * 说明:迭代器实现类
     */
    public class IteratorImpl<T> implements Iterator {
        //持有聚合对象引用
        private Group<T> mGroup;
        //当前游标指向的索引处
        private int curIndex;
    
        public IteratorImpl(Group group) {
            mGroup = group;
        }
    
        @Override
        public boolean hasNext() {
            //当游标的指向索引比元素总数少,说明还有next
            return curIndex < mGroup.size();
        }
    
        @Override
        public T next() {
            //返回当前索引处元素
            T el = mGroup.get(curIndex);
            //当游标的指向索引后移
            curIndex++;
            return el;
        }
    }
    
    4.集合对象实现类
    /**
     * 作者:张风捷特烈
     * 时间:2018/10/1 0001:23:20
     * 邮箱:1981462002@qq.com
     * 说明:集合对象实现类
     */
    public class GroupImpl<T> implements Group<T> {
        //维护一个数组盛放元素
        private T[] data;
        //维护内部元素个数
        private int size = 0;
    
        public GroupImpl() {
            //为了简单,使用固定容积50
            data = (T[]) new Object[50];
        }
    
        @Override
        public void add(T el) {
            data[size] = el;
            size++;
        }
    
        @Override
        public T get(int index) {
            return data[index];
        }
    
        @Override
        public Iterator<T> iterator() {
            return new IteratorImpl(this);
        }
    
        @Override
        public int size() {
            return size;
        }
    }
    
    5.测试
    public class Client {
        public static void main(String[] args) {
            GroupImpl<Student> classRoom = new GroupImpl<>();
            classRoom.add(new Student(1, "捷特"));
            classRoom.add(new Student(2, "龙少"));
            classRoom.add(new Student(3, "巫缨"));
    
            for (int i = 0; i < classRoom.size(); i++) {
                System.out.println(classRoom.get(i));
            }
    
            Iterator<Student> it = classRoom.iterator();
    //        System.out.println(it.next());//Student{id=1, name='捷特'}
    //        System.out.println(it.next());//Student{id=2, name='龙少'}
    //        System.out.println(it.next());//Student{id=3, name='巫缨'}
    //        System.out.println(it.next());//null
            
            while (it.hasNext()) {
                System.out.println(it.next());
    //            Student{id=1, name='捷特'}
    //            Student{id=2, name='龙少'}
    //            Student{id=3, name='巫缨'}
            }
        }
    }
    
    9414344-3a7317fe472378aa.png
    迭代器模式例.png

    二、ArrayList中的Iterator

    java中内置的聚合类,顶尖接口Collection实现了Iterable接口,也就是可迭代

    1.Iterable接口中定义了获取Iterator对象的函数iterator()
    public interface Iterable<T> {
        Iterator<T> iterator();
    
    2.Collection继承了Iterable接口也必然继承它的方法
    public interface Collection<E> extends Iterable<E> {
        Iterator<E> iterator();
    
    3.同样List接口继承了Collection接口也必然这个方法
    public interface List<E> extends Collection<E> {
        Iterator<E> iterator();
    
    4.java中自带的迭代器:Iterator
    public interface Iterator<E> {
        //是否拥有下一个元素
        boolean hasNext();
        //下一个元素
        E next();
    
        default void remove() {
            throw new UnsupportedOperationException("remove");
        }
    
        default void forEachRemaining(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            while (hasNext())
                action.accept(next());
        }
    }
    
    4.该方法在ArrayList中的实现

    private class Itr implements Iterator<E>说明该迭代器实现类Itr是ArrayList的内部类
    这样做就不必让Itr持有ArrayList的引用,简单一些。

        public Iterator<E> iterator() {
            //返回一个迭代器实现类对象
            return new Itr();
        }
    
        private class Itr implements Iterator<E> {
            int cursor;       // 游标:将要返回的元素索引
            int lastRet = -1; // 最后一个被返回元素的索引,-1表示没有返回过
            int expectedModCount = modCount;//期望的修改次数与真是修改次数置同
    
           //私有化构造方法
            Itr() {}
    
            public boolean hasNext() {
                //当游标未达到元素总数时,表明还有下一个元素
                return cursor != size;
            }
    
            @SuppressWarnings("unchecked")
            public E next() {
                checkForComodification();//见I--1
                int i = cursor;//用变量i暂存游标位置
                if (i >= size)//游标位置大于等于size,抛出异常
                    throw new NoSuchElementException();
                //获取当前ArrayList的成员变量:elementData(当前数组)
                Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length)//游标位置大于当前数组总长,抛出异常
                    throw new ConcurrentModificationException();
                cursor = i + 1;//游标后移
                //维护lastRet为i,即返回的元素索引
                return (E) elementData[lastRet = i];
            }
    
            public void remove() {
                if (lastRet < 0)//即没有调用过next()方法:见Test-1
                    throw new IllegalStateException();
                checkForComodification();//见I--1
                try {
                    ArrayList.this.remove(lastRet);//移除操作
                    cursor = lastRet;//索引指向刚才移除的索引位
                    lastRet = -1;//最后返回的索引置为-1,[由此可见不能连续执行两次iterator.remove()操作]
                    expectedModCount = modCount;//期望的修改次数与真是修改次数置同
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }
    
            @Override//测试见:Test-2
            public void forEachRemaining(Consumer<? super E> action) {
                Objects.requireNonNull(action);//判断是否为空,空则抛空指针
                final int size = ArrayList.this.size;//size记录元素中个数
                int i = cursor;//用变量i暂存游标位置
                if (i < size) {
                    final Object[] es = elementData;//记录数组
                    if (i >= es.length)//越界
                        throw new ConcurrentModificationException();
                    for (; i < size && modCount == expectedModCount; i++)
                        action.accept(elementAt(es, i));//见I--2
                    // update once at end to reduce heap write traffic
                    cursor = i;
                    lastRet = i - 1;
                    checkForComodification();///见I--1
                }
            }
        }
    

    I--1:查看期望修改次数与实际修改次数是否相同
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
    

    I--2:返回一个数组指定索引位置的元素
       static <E> E elementAt(Object[] es, int index) {
            return (E) es[index];
        }
    

    Test-1
            ArrayList<String> aList = new ArrayList();
            aList.add("b");
            aList.add("a");
            aList.add("c");
            
            Iterator<String> iterator = aList.iterator();
            iterator.remove();//直接使用移除会报异常
            //Exception in thread "main" java.lang.IllegalStateException
    
            ArrayList<String> aList = new ArrayList();
            aList.add("b");
            aList.add("a");
            aList.add("c");
    
            Iterator<String> iterator = aList.iterator();
            String first = iterator.next();
            System.out.println(first);//b
            System.out.println(aList);//[b, a, c]
            //执行过iterator.next(),lastRet指向返回元素的位置,就不再是0,调用remove就不会异常了
            iterator.remove();//移除iterator最后返回的元素
            System.out.println(aList);//[a, c]
    
            Iterator<String> iterator = aList.iterator();
            String first = iterator.next();
            String second = iterator.next();
            System.out.println(first);//b
            System.out.println(second);//a
            System.out.println(aList);//[b, a, c]
            //执行两次iterator.next(),iterator最后返回的元素为a,移除之
            iterator.remove();
            System.out.println(aList);//[b, c]
    

    Test-2
    ArrayList<String> aList = new ArrayList();
    aList.add("b");
    aList.add("a");
    aList.add("c");
    Iterator<String> iterator = aList.iterator();
    
    iterator.forEachRemaining(s -> {
        s += "-Hello";
        System.out.print(s+" ");//b-Hello a-Hello c-Hello 
    });
    

    就酱紫,Iterator这个类的用法差不多也就这些


    后记:捷文规范

    1.本文成长记录及勘误表
    项目源码 日期 备注
    V0.1--无 2018-10-2 Java容器源码攻坚战--第一战:Iterator
    V0.2--无 - -
    2.更多关于我
    笔名 QQ 微信 爱好
    张风捷特烈 1981462002 zdl1994328 语言
    我的github 我的简书 我的CSDN 个人网站
    3.声明

    1----本文由张风捷特烈原创,转载请注明
    2----欢迎广大编程爱好者共同交流
    3---个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
    4----看到这里,我在此感谢你的喜欢与支持

  • 相关阅读:
    计算系数
    N皇后问题
    矩阵取数游戏
    过河卒
    经营与开发
    软件开发记录01
    搭建android开发环境
    软件工程结对作业01
    学习总结和教师评价
    站立会议14
  • 原文地址:https://www.cnblogs.com/toly-top/p/9781856.html
Copyright © 2011-2022 走看看