A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

# 迭代器源码解析
## 什么是迭代器?
​ 迭代器是为容器而生,它本质上就是一种遍历的算法。因为容器的实现千差万别,很多时候不可能知道如何去遍历一个单列集合对象的元素。Java为我们提供了使用迭代的接口。
​ 注:以下源码截图中的蓝色字都为注释,可以忽略掉!!!

java提供的迭代器的接口中定义了三个方法:
   -  hasNext() :判断是否还有元素
   -  next() :获取指向的元素
   -  remove() :删除指向的元素
上面只是java定义的接口,想弄清楚具体的原理,我们还需要查看具体的实现,也就是迭代器接口的具体的实现  ,该文章只是就ArrayList集合中迭代器实现进行讲解。
## 什么样的容器可以使用迭代器进行遍历元素呢?
​ 要想使用迭代器进行遍历的容器必须实现Iterable接口。那么为什么呢?我们先来看看Iterable接口定义了哪儿方法

通过源码的查看,Iterable接口中只定义了一个方法,也就是获取迭代器的方法,故一个容器需要使用迭代器进行遍历,必须给出具体的迭代器的方法。我们知道单例集合可以使用迭代器遍历,那么单例集合一定也继承能了该接口。


## ArrayList集合迭代器实现
​ ArrayList作为Colleciton接口的具体的子实现类,必须重写父接口中所有的抽象方法,当然也包括Iterable接口的获取iterator()方法



通过源码查看iterator()方法直接返回了Itr类的对象,而Itr类是ArrayList类中的私有的成员内部类,也就是说ArrayList类中定义了一个只适合ArrayList集合元素的遍历的迭代器。
### Itr迭代器成员遍历解析
- cursor :记录下一个要返回元素的索引,默认值为0
- lastRet :记录要返回元素的索引,默认值为-1
- expectedModCount :modCount是ArrayList中定义的变量,用来记录集合中元素的修改,添加元素和删除元素该变量都会自增1,就是给迭代器的使用的,稍后我们进行具体的讲解。
### Itr迭代器成员方法的解析
#### hasNext()方法:
size变量是ArrayList集合中记录元素的个数,cursor变量会在next()方法中没调用一次自增一次,所以只要cursor变量的值不等于集合中元素的个数,那就说明还有元素,返回true。
#### next()方法:

next()方法中第一行就调用了checkForComodification(),我们来看看该方法的具体的实现。

expectedModCount 变量是Itr迭代器类中的成员变量,一开始将ArrayList集合中的元素的修改的次数modCount赋予该变量,如果使用集合中的添加或者删除方法,ArrayList集合中的成员变量modCount都会自增1,而没有重新给expectedModCount 变量赋值,所以这两个变量的值就肯定不相等,那么就会抛出ConcurrentModificationException异常,也就是并发修改异常。也就是说只要集合中的元素的个数发生的改变就会抛出并发修改异常。
如next方法图的833行,做了一个判断,如果记录下一个元素的索引大于集合中元素的个数,就抛出NoSuchElementException异常
如next方法图的835行,如果异常都没有抛异常,则将集合中所有的元素复制一份给迭代器的elementData数组,couror变量自增1指向于下一个元素,返回couror之前指向的元素。
#### remove()方法:

第843行的判断是在使用迭代器的next()方法之前不允许使用remove()方法,否则抛出IllegalStateException异常。
checkForComodification()的解析见上面的分析。如果上面都没有抛出异常,则使用 ArrayList.this.remove(lastRet)集合中的remove方法删除正在指向的元素,并将lastRet变量重新赋值为-1。重新同步expectedModCount变量的值,这样就确保了使用迭代器的remove方法不会出现并发修改异常的发生。



0 个回复

您需要登录后才可以回帖 登录 | 加入黑马