当前位置: 移动技术网 > IT编程>软件设计>设计模式 > Java设计模式(迭代器模式 - 概念及jdk迭代器解析)

Java设计模式(迭代器模式 - 概念及jdk迭代器解析)

2020年08月10日  | 移动技术网IT编程  | 我要评论
学习设计模式不光要学习设计模式的思想,还要去深入理解,为什么要用这个设计模式。如何深入理解?读优秀的框架代码,看别人代码,了解它们的使用场景。 - - - 博主老师(感谢他)本文先介绍了迭代器模式的概念,并介绍了jdk中的迭代器源码,最后聊了下为什么需要迭代器模式。迭代器模式1、概念2、jdk中的迭代器3、为什么要有迭代器模式1、概念定义:提供一种方法顺序访问一个容器使用场景:遍历一个容器对象。对于开发者来说,几乎不会自己去实现一个迭代器。因为jdk已经帮我们实现好了。我们主要是对.

学习设计模式不光要学习设计模式的思想,还要去深入理解,为什么要用这个设计模式。
如何深入理解?读优秀的框架代码,看别人代码,了解它们的使用场景。 - - - 博主老师(感谢他)

本文先介绍了迭代器模式的概念,并介绍了jdk中的迭代器源码,最后聊了下为什么需要迭代器模式。


1、概念

定义:提供一种方法顺序访问一个容器

使用场景:遍历一个容器对象。

对于开发者来说,几乎不会自己去实现一个迭代器。因为jdk已经帮我们实现好了。我们主要是对迭代器模式做个了解,看看Java中是怎么去实现迭代器模式的。

2、jdk中的迭代器

我们遍历一个list的时候,经常会用到foreach,如下

public class Test {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        for (String aList : list) {
            System.out.println(aList);
        }
    }
} 

将Test类,javac一下,生成class文件,再拖到Intellij IDEA中,发现变成了Iterator的方式。
在这里插入图片描述

我们重点看下ArrayList的迭代器是怎么实现的

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { public Iterator<E> iterator() { return new Itr(); } } 

iterator方法返回了一个Itr类

首先Itr类实现了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());
    }
} 

接下来看Itr

private class Itr implements Iterator<E> {
    // next方法返回的元素的下标
    int cursor;       // index of next element to return
    // 最近一次调用next返回元素的下标(默认-1)
    int lastRet = -1; // index of last element returned; -1 if no such
    int expectedModCount = modCount;

    // 判断是否还有元素,通过游标是否等于size判断
    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;
        // 我们知道,arrayList是通过数组实现的
        return (E) elementData[lastRet = i];
    }
    
    // 删除一个元素
    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            // 移除的是上一次next返回的元素
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public void forEachRemaining(Consumer<? super E> consumer) {
        Objects.requireNonNull(consumer);
        final int size = ArrayList.this.size;
        // 从cursor开始
        int i = cursor;
        if (i >= size) {
            return;
        }
        final Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length) {
            throw new ConcurrentModificationException();
        }
        // 对cursor - (size-1)的元素做处理,处理的行为是入参定义的函数
        while (i != size && modCount == expectedModCount) {
            consumer.accept((E) elementData[i++]);
        }
        // update once at end of iteration to reduce heap write traffic
        cursor = i;
        lastRet = i - 1;
        checkForComodification();
    }

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

3、为什么要有迭代器模式

对于容器对象的访问,必然会涉及遍历算法。如果将遍历封装到容器中,对于容器来说,承担的功能有点多。如果让用户自己实现,那又必须暴露容器的内部实现。所以使用迭代器模式,在客户访问类与容器体之间插入一个第三者-迭代器。

而且Java Iterator统一了迭代方法,不管是list,还是map,或者set等,都可以用Iterator遍历。


https://blog.csdn.net/u010647035/article/details/79826457

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网