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----看到这里,我在此感谢你的喜欢与支持

  • 相关阅读:
    light oj 1105 规律
    light oj 1071 dp(吃金币升级版)
    light oj 1084 线性dp
    light oj 1079 01背包
    light oj 1068 数位dp
    light oj 1219 树上贪心
    light oj 1057 状压dp TSP
    light oj 1037 状压dp
    矩阵快速幂3 k*n铺方格
    矩阵快速幂2 3*n铺方格
  • 原文地址:https://www.cnblogs.com/toly-top/p/9781856.html
Copyright © 2011-2022 走看看