集合- Iterator(迭代器)源码详解以及自定义迭代器实现

版权声明:中华人民共和国持有版权 https://blog.csdn.net/Fly_Fly_Zhang/article/details/87721790

迭代器:是一种设计模式,提供了一种方法,来对集合,容器进行遍历的方式,不需要关注底层数据结构和数据类型,来达到底层和上层遍历解耦的目的。

集合如何获得一个迭代器:集合要具有iterator 方法需要实现iterable接口,要自定义一个迭代器内部类,类需要实现Iterator接口;

  • iterator方法:
 public Iterator<E> iterator() {
        return new Itr();//具体的迭代器需要自定义一个内部类实现Iterator接口
    }
    
  • 集合自定义迭代器实现:
public class DIYArrayList<T> implements Iterable<T> {
    private T[] data;//存储元素数组
    private int size;//元素个数
    public DIYArrayList() {
        this(10);
    }
    public DIYArrayList(int campcity) {
        if (campcity < 0){
            try {
                throw new IllegalAccessException("参数异常");
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        data = (T[]) new Object[campcity];
        size = 0;
    }

    //集合是否满
    private boolean isFull() {
        return size == data.length;
    }

    //扩容
    private void grow() {
        int newLength = size+size>>1;//1.5倍扩容
        data = Arrays.copyOf(data, newLength);
    }

    //范围判断
    private boolean checkRange(int index) {
        if (index< 0 || index >= size)
             throw new IndexOutOfBoundsException();

        return true;
    }
    //重写集合转换数组方法
    @Override
    public String toString() {
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < size; i++) {

            buffer.append(data[i]+" ");
        }
        return buffer.toString();
    }
     //添加元素
    public boolean add(T e) {
        if (isFull()) {//数组已满,对数组进行扩充
            grow();
        }
        data[size++]=e;
        return true;
    }
    //获取指定角标的集合元素
    public T get(int index) {
        checkRange(index); //对角标进行合法性检查
        return data[index];
    }
    //对集合指定角标元素进行删除
    public T remove(int index) {
        checkRange(index);
        T v = data[index];
        int mov = size -index-1;
        System.arraycopy(data, index+1, data,index,mov);
        data[--size] = null;
        return v;
    }
    //对集合指定元素进行删除
    public boolean remove (T e) {
    //注意对null值和非null进行区别对待
        if (e == null) { 
            for (int i = 0; i < size; i++) {
                if (data[i] == null) {
                    int mov = size -i-1;
                    System.arraycopy(data, i+1, data,i,mov);
                    data[--size] = null;
                    return true;
                }
            }
        } else {
            for (int i = 0; i < size; i++) {
                if (e.equals(data[i])) {
                    int mov = size -i-1;
                    System.arraycopy(data, i+1, data,i,mov);
                    data[--size] = null;
                    return true;
                }
            }
        }
        return false;
    }
   //获取一个迭代器
    @Override
    public Iterator<T> iterator() {
        return new Itr();
    }

    class Itr implements Iterator<T> {
        private int afterindex;//前一个位置
        private int beforeindex;//后一个位置
        public Itr(){
              beforeindex=-1;
        }
        @Override
        public boolean hasNext() {
            return afterindex != size;
        }

        @Override
        public T next() {
            int i = afterindex;
            afterindex++;
            T v = data[i];
            beforeindex = i;
            return v;
        }

        @Override
        public void remove() {
            // T next = next();
            //DIYArrayList.this.remove(next);
            //注意,这里只能调用集合中的角标删除方法,因为一个集合中可能有多个与删除元素相同的元素,
            //这样可能删除的元素并不是迭代器指定那个元素;
            DIYArrayList.this.remove(beforeindex ); //删除的是上一次next()的值
            afterindex=beforeindex; //等效于afterindex--
            beforeindex = -1;
        }
    }

    public static void main(String[] args) {
        DIYArrayList<Integer> arrayList = new DIYArrayList<>();
        arrayList.add(12);,
        arrayList.add(34);
        arrayList.add(56);
        System.out.println(arrayList);
        Iterator<Integer> iterator = arrayList.iterator();
        while (iterator.hasNext()) {
          Integer next = iterator.next();
          if (next == 33) {
               iterator.remove(); //remove()必须与next()配合使用,源码也是这样设计的
            }
        }
        System.out.println(arrayList.size);
    }
}

Iterator方法介绍以及源码分析
  • boolean hasNext():判断集合是否还有元素,true则表示还存在元素
  • E next() : 返回当前数据
  • void remove():删除元素:
注意:
  • hasNext()和next()需要配合使用,每次next()之前都必须调用一次hasNext()进行判断;
  • 每次调用remove()之前必须调用一次next(),那么也就必须调用hasNext();
  • 版本号的实例分析:
 Iterator<Integer> iterator = arrayList.iterator();
        while (iterator.hasNext()) {
            Integer value = iterator.next();
            if (value == 33) {
                 arrayList.remove(Integer.valueOf(33)); 
                 //对集合进行增删改查,集合版本号会发生变化,迭代器的不会发生变化
            }
               iterator.remove(); 
               //在迭代器进行删除时,迭代器的版本副本与集合的版本号不同,抛出并发行异常

        }

源码解析
private class Itr implements Iterator<E> {
        int cursor;       // hasNext()表示的坐标
        int lastRet = -1; // next()当前坐标
        int expectedModCount = modCount; 
        //版本号,统一集合和迭代器的版本号,如果集合发生修改,那么集合的版本号就会发生变化,
        //那么集合和迭代器的版本号就会不同意,会发生并发性异常;

        Itr() {}
        //判断下一个是否有下一个元素
        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();//版本检查
            int i = cursor;
            if (i >= size)//next()角标位置已经大于集合中元素的个数
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
           //上一个if没有抛出异常,那么说明size合法,这里按理不会出现i大于数组长度的问题,
           //如果出现说明在迭代器创建后集合发生了改变,因此应该抛一个并发性异常
                throw new ConcurrentModificationException();
            cursor = i + 1;//下一次hasNext()判断角标
            return (E) elementData[lastRet = i];//返回本次hasNext()确定有效的角标元素
        }

        public void remove() {
            if (lastRet < 0)//删除元素的角标不合法
                throw new IllegalStateException();
            checkForComodification();//版本检查

            try {
                ArrayList.this.remove(lastRet);
                //调用集合的remove()方法进行删除操作
                cursor = lastRet;
                //删除完成后,cursor角标的元素移到了lastRet位置,
                lastRet = -1;
                //这句意味着,每次remove()之前必须进行next()操作
                expectedModCount = modCount;
                //本次删除操作,迭代器是知晓的,所以统一版本号
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

    
        final void checkForComodification() {
        //版本检查,如果不同则抛出并发性异常,说明有多个线程对集合进行操作;
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

猜你喜欢

转载自blog.csdn.net/Fly_Fly_Zhang/article/details/87721790
今日推荐