初学迭代器2, ArrayList的Iterator实现

学习的是ArrayList里面的迭代器.

JDK1.7 里面的源码如下:

private class Itr implements Iterator {

int cursor; // index of next element to return

int lastRet = -1; // index of last element returned; -1 if no such

int expectedModCount = modCount;

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;

return (E) elementData[lastRet = i];

}

public void remove() {

if (lastRet < 0)

throw new IllegalStateException();

checkForComodification();

try {

ArrayList.this.remove(lastRet);

cursor = lastRet;

lastRet = -1;

expectedModCount = modCount;

} catch (IndexOutOfBoundsException ex) {

throw new ConcurrentModificationException();

}

}

final void checkForComodification() {

if (modCount != expectedModCount)

throw new ConcurrentModificationException();

}

}

cursor 这是一个游标, 用于判断当前迭代器指向容器中对象的索引, 简单点说cursor现在是指向第几个元素
lastRet 用来判断是不是正确调用remove
expectedModCount 这个我也不是很懂...现在感觉是用来判断是不是出现了并发修改用的

先看hasNext()这个方法, 感觉设计的人很聪明, 利用游标还有索引的结合就可以简单地构造了一个迭代器.
通过cursor和size来比较大小, 由于每次调用next()方法的时候,cursor都会自增1, 就是做指向了容器中下一个元素,
所以一旦cursor大于或者等于size就会抛异常, (因为cursor实际上指向的是对象的索引, 然后再获取该地址中的引用,这是我根据数组来思考得出来的, 欢迎指正)
保证了每一次迭代都会是容器里面存在的元素
//
next():
这里明确了迭代的过程中不允许对容器的长度进行并发修改. 因为本来容器中长度为10,
在迭代的过程中, 突然有一个线程来在容器中添加了一个元素, 这样就会导致遍历不对等不可预测的结果, 因此不允许并发修改.
通过了检测游标是否超出索引范围(就是大于或者等于size)后, 方法体里面首先会记住当前游标的值, 也就是索引值, 因为这个值是迭代器中当前迭代对象在容器中的索引值.接下来就是再次进行并发检测了, "ArrayList.this.elementData"这句代码是获取当前容器的全部对象,注意是每次迭代中都会重新获取一遍(所以中间如果发生了并发修改就会导致不可预测的结果).
由于在前面已经执行过了"索引与游标比较"和"并发检测", 所以按道理来说i是肯定不会超出索引, 所以一旦超出了, 就证明有一个线程对容器进行了操作, 导致i超出了索引了, 指向容器中一个不存在的元素.
接着就是获取当前迭代的对象(i), 然后cursor自增(游标指向了下一个元素), 注意这里是"elementData[lastRet = i]",是给lastRet给赋值了, 用于remove()方法.(原来API上说如果要调用remove, 就必须要先调用next方法, 就是这个原因)
//
​remove():
根据之前对next的解释, 如果没有调用next的话, lastRet就是等于-1, 所以抛出异常(非法状态异常).
在写解释的时候, 我突然想到了, 迭代器处于的当前线程是可以对容器进行操作的, 比如就像这个remove, 只是不能进行并发修改(这里欢迎指正哈)
每次移除都会移除迭代器最后返回的一个对象, 因为上面next里面说了lastRet是等于i的(而不是移除cursor指向的对象)
移除容器里面的元素之后, 被移除元素后面的元素都需要把索引往前面挪一下,所以要把迭代的位置重新调整,
将lastRet的值赋给了cursor(这里cursor指向的对象并没有发生改变, 只是这个对象在容器中的位置发生了改变而已).
再把-1赋值给lastRet(移除之前又要调用一次next咯....)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值