首页 > 其他分享 >Day25 迭代器之Iterator底层

Day25 迭代器之Iterator底层

时间:2024-03-24 15:59:05浏览次数:19  
标签:操作数 elementData Iterator 迭代 Day25 元素 遍历

Day25 迭代器之Iterator底层

一、迭代器

1、概念:

迭代器(Iterator)是一种用于遍历集合(Collection)元素的接口,它提供了统一的方式来访问集合中的元素,而不暴露集合的内部结构。通过迭代器,我们可以依次访问集合中的每个元素,进行遍历和操作。

2、使用步骤:

  1. 获取集合的迭代器

    Iterator<String> iterator = collection.iterator();
    
  2. 遍历集合

    使用while循环和hasNext()方法来判断是否还有下一个元素:

    while (iterator.hasNext()) {
        String element = iterator.next();
        // 对元素进行操作
    }
    
  3. 删除元素

    在遍历过程中,可以使用迭代器的remove()方法来删除当前元素:

    iterator.remove();
    

注意: 迭代器提供了一种安全且高效的遍历集合的方式,可以在遍历过程中对集合进行增删改查操作,而不会出现并发修改异常。迭代器还支持快速失败机制,即在遍历过程中如果集合结构发生变化(如添加或删除元素),会抛出ConcurrentModificationException异常,以确保遍历的安全性。

二、Iterator底层源码

注意:研究源码,必须找场景!!!

//场景
ArrayList<String> list = new ArrayList<>();
		
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");

Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String element = it.next();
    System.out.println(element);
}
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    
    //外部操作数
    //作用:记录修改元素的次数(添加、删除会让该变量++)
    protected transient int modCount = 0;//modCount - 5
}
public class ArrayList<E> extends AbstractList<E> implements List<E>{
    //元素个数
    private int size;//size - 4
    //数据容器 - ["aaa","bbb","ccc","ddd",null,null,null,null,null,null]
    transient Object[] elementData;
    
    //e - ddd
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);//判断是否扩容
        elementData[size++] = e;
        return true;
    }
    
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }
    
    public Iterator<E> iterator() {
        return new Itr();
    }
    
    
    //ArrayList类的内部类 -- 实现了遍历元素的功能
    private class Itr implements Iterator<E> {
        
        int cursor;       // 游标 - 4
        int lastRet = -1; // 当前元素的下标 - 3
        int expectedModCount = modCount;//内部操作数 - 5

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

        @SuppressWarnings("unchecked")
        public E next() {
            
            /**
            	思考题:为什么在获取元素时,会先判断外部操作数是否等于内部操作数
            		考虑到遍历元素时,如果添加或删除元素,会导致数据个数变化
            		遍历时就有可能出现脏数据,如果外部操作数和内部操作数不相同就以为数据不同意,就报错!
            */
            checkForComodification();//判断外部操作数是否等于内部操作数,如果不等于就报错
            int i = cursor;//i - 3
            if (i >= size)
                throw new NoSuchElementException();
            //获取外部类的成员属性 -- elementData
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            
            //elementData -- 获取的是ArrayList(外部类的)elementData -> Object[] elementData;
            //Object类型的元素强转为集合中真实类型的元素
            // --> elementData[3] --> Object类型的数据需要强转为String类型
            return (E) elementData[lastRet = i];//elementData[3]
        }
        
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

        //重写了Iterator接口中的remove()
        public void remove() {
            //判断当前元素的下标是否小于0
            if (lastRet < 0)
                throw new IllegalStateException();
            
            //判断外部操作数是否和内部操作数一致,不一致就会报错
            checkForComodification();

            try {
                //利用ArraList类的remove()去删除元素
                ArrayList.this.remove(lastRet);
                //把当前元素的下标赋值给游标
                cursor = lastRet;
                //把-1赋值给lastRet
                lastRet = -1;
                //重新把外部操作数赋值给内部操作数
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
        
    }
    
}
/**
	
	思考题:为什么迭代器是一个接口,不是类???
		因为Java提供了很多的集合,不同的集合实现增删改查的原理是不一样的,
		所以,不同的集合都实现了各自遍历元素的代码(实现了各自的迭代器)
*/
//迭代器的接口
public interface Iterator<E> {
   
    //判断是否有可迭代的元素
    boolean hasNext();

    //获取下一个元素
    E next();

    //删除元素的默认方法(作用:给实现类去重写,如果实现类可以选择不重写,意味着遍历时不能删除元素,当然实现类可以选择重写,那么就意味着这个迭代器可以在遍历元素时删除元素)
    default void remove() {
        //抛出异常 -- 删除异常
        throw new UnsupportedOperationException("remove");
    }
}

标签:操作数,elementData,Iterator,迭代,Day25,元素,遍历
From: https://blog.csdn.net/yjp1240201821/article/details/136989155

相关文章

  • python之迭代器和生成器的使用方式
    下面我将分别介绍迭代器和生成器的使用示例:迭代器示例:迭代器是一种对象,它可以在遍历时逐个访问元素而不需要将所有元素加载到内存中。下面是一个简单的迭代器示例,该迭代器生成斐波那契数列的前n个数字:classFibonacciIterator:def__init__(self,n):self.n=......
  • 迭代器切片/itertools.islice/yield返回
    使用itertools.isliceitertools.islice允许您对迭代器进行切片操作,这是处理生成器切片的推荐方法。它不需要将生成器的所有元素加载到内存中,因此仍然保持了生成器的高效性。这里是如何使用islice来获取前四个元素的示例:fromitertoolsimportislice#假设dou.get_user_post返......
  • 算法打卡day25|回溯法篇05|Leetcode 491.递增子序列、46.全排列、47.全排列 II
     算法题Leetcode491.递增子序列题目链接:491.递增子序列大佬视频讲解:递增子序列视频讲解 个人思路和昨天的子集2有点像,但昨天的题是通过排序,再加一个标记数组来达到去重的目的。而本题求自增子序列,是不能对原数组进行排序的,因为排完序的数组都是自增子序列了。解决......
  • 在for循环中删除迭代器所指内容崩溃
    经常在网上看到“容器中删除的只要不是最后一个元素,循环就会崩溃”其实不然,经过测试;容器中使用迭代器循环访问,只要删除迭代器所指元素后,继续for,不管你删除的是第一个还是最后一个,或者中间的某一个,只要不跳出来,就会崩溃;首先,for循环,++或者--,都是在for循环体执行完一次后执行;所以当......
  • TypeScript之Symbol和迭代器
    Symbols介绍自ECMAScript2015起,symbol成为了一种新的原生类型,就像number和string一样。symbol类型的值是通过Symbol构造函数创建的。letsym1=Symbol();letsym2=Symbol("key");//可选的字符串keySymbols是不可改变且唯一的。letsym2=Symbol("key");let......
  • 【python】(02)初识迭代器Iterator
    系列文章回顾【python】(01)初识装饰器Decorator【python】(02)初识迭代器Iterator文章目录一.迭代器的定义二.迭代器的作用三.实际代码示例四.使用注意事项五.常见问题迭代器是Python中非常重要的概念,通过灵活运用迭代器可以实现高效的数据遍历和处......
  • 每日一看大模型新闻(2024.1.20-1.21)英伟达新对话QA模型准确度超GPT-4,却遭吐槽:无权重代
    1.产品发布1.1韩国Kakao:推出多模态大模型Honeybee发布日期:2024.1.20KakaounveilsmultimodallargelanguagemodelHoneybee-TheKoreaTimes主要内容:韩国科技巨头Kakao今天宣布他们已经开发了一种名为“蜜蜂”(Honeybee)的多模态大语言模型。据Kakao称,“蜜蜂”能够同时......
  • 哈希技术解析:从哈希函数到哈希桶迭代器的全面指南
    文章目录引言一、哈希表与哈希函数1、哈希表的基本原理2、哈希函数的作用与特点3、哈希冲突的处理方法二、哈希桶及其迭代器1、哈希桶a.定义哈希桶结构b.哈希函数c.哈希桶的插入、查找、删除2、哈希桶的迭代器a.类型定义与成员变量b.构造函数c.解引用与比较操作d.递......
  • 中文编程入门(Lua5.4.6中文版)第九章 Lua 迭代器 参考种田游戏
    迭代器(iterator)在游戏开发中扮演着重要角色,尤其是在Lua语言中。它是一种特殊的数据结构,能够逐个访问集合中的元素,犹如一位探险家穿越种田游戏的领土,逐一揭示各个城市与资源。在Lua中,迭代器以一种强大的机制实现,它可以跟踪并遍历表或其他集合类型的每一个项目。其中,泛型for循环......
  • 如何系统的学习Python——迭代器和生成器
    在Python中,迭代器(Iterators)和生成器(Generators)是用于处理可迭代对象的重要工具。它们允许你按需产生值,而不是一次性生成所有值,从而在处理大量数据时更加高效。下面是关于迭代器和生成器的详细解释:迭代器(Iterators):可迭代对象:在Python中,可迭代对象是实现了__iter__()方......