=a14c id=zoom>
Java源码分析:深入探讨Iterator模式
java.util包中包含了
![](/icons/20832yi.gif)
系列重要
![](/icons/20832de.gif)
集合类
![](/icons/20832dou2.gif)
本文将从分析源码入手
![](/icons/20832dou.gif)
深入研究
![](/icons/20832yi.gif)
个集合类
![](/icons/20832de.gif)
内部结构
![](/icons/20832dou.gif)
以及遍历集合
![](/icons/20832de.gif)
迭代模式
![](/icons/20832de.gif)
源码实现内幕
![](/icons/20832dou2.gif)
下面我们先简单讨论
![](/icons/20832yi.gif)
个根接口Collection
![](/icons/20832dou.gif)
然后分析
![](/icons/20832yi.gif)
个抽象类AbstractList和它
![](/icons/20832de.gif)
对应Iterator接口
![](/icons/20832dou.gif)
并仔细研究迭代子模式
![](/icons/20832de.gif)
实现原理
![](/icons/20832dou2.gif)
本文讨论
![](/icons/20832de.gif)
源代码版本是JDK 1.4.2
![](/icons/20832dou.gif)
![](/icons/20832yinwei.gif)
JDK 1.5在java.util中使用了很多泛型代码
![](/icons/20832dou.gif)
为了简化问题
![](/icons/20832dou.gif)
所以我们还是讨论1.4版本
![](/icons/20832de.gif)
代码
![](/icons/20832dou2.gif)
集合类
![](/icons/20832de.gif)
根接口Collection
Collection接口是所有集合类
![](/icons/20832de.gif)
根类型
![](/icons/20832dou2.gif)
它
![](/icons/20832de.gif)
![](/icons/20832yi.gif)
个主要
![](/icons/20832de.gif)
接口思路方法是:
boolean add(Object c)
add
![](/icons/20832kh.gif)
思路方法将添加
![](/icons/20832yi.gif)
个新元素
![](/icons/20832dou2.gif)
注意这个思路方法会返回
![](/icons/20832yi.gif)
个boolean
![](/icons/20832dou.gif)
但是返回值不是表示添加成功和否
![](/icons/20832dou2.gif)
仔细阅读doc可以看到
![](/icons/20832dou.gif)
Collection规定:如果
![](/icons/20832yi.gif)
个集合拒绝添加这个元素
![](/icons/20832dou.gif)
无论任何原因
![](/icons/20832dou.gif)
都必须抛出异常
![](/icons/20832dou2.gif)
这个返回值表示
![](/icons/20832de.gif)
意义是add
![](/icons/20832kh.gif)
思路方法执行后
![](/icons/20832dou.gif)
集合
![](/icons/20832de.gif)
内容是否改变了(就是元素有无数量
![](/icons/20832dou.gif)
位置等变化)
![](/icons/20832dou.gif)
这是由具体类实现
![](/icons/20832de.gif)
![](/icons/20832dou2.gif)
即:如果思路方法出错
![](/icons/20832dou.gif)
总会抛出异常;返回值仅仅表示该思路方法执行后这个Collection
![](/icons/20832de.gif)
内容有无变化
![](/icons/20832dou2.gif)
类似
![](/icons/20832de.gif)
还有:
boolean addAll(Collection c);
boolean remove(Object o);
boolean removeAll(Collection c);
boolean re
![](/icons/20832main.gif)
All(Collection c);
Object
![](/icons/20832zhk2.gif)
toArray
![](/icons/20832kh.gif)
思路方法很简单
![](/icons/20832dou.gif)
把集合转换成
![](/icons/20832shuzu.gif)
返回
![](/icons/20832dou2.gif)
Object
![](/icons/20832zhk2.gif)
toArray(Object
![](/icons/20832zhk2.gif)
a)思路方法就有点复杂了
![](/icons/20832dou.gif)
首先
![](/icons/20832dou.gif)
返回
![](/icons/20832de.gif)
Object
![](/icons/20832zhk2.gif)
仍然是把集合
![](/icons/20832de.gif)
所有元素变成
![](/icons/20832de.gif)
![](/icons/20832shuzu.gif)
![](/icons/20832dou.gif)
但是类型和参数a
![](/icons/20832de.gif)
类型是相同
![](/icons/20832de.gif)
![](/icons/20832dou.gif)
比如执行:
String
![](/icons/20832zhk2.gif)
o = (String
![](/icons/20832zhk2.gif)
)c.toArray(
![](/icons/20832new.gif)
String[0]);
得到
![](/icons/20832de.gif)
o实际类型是String
![](/icons/20832zhk2.gif)
![](/icons/20832dou2.gif)
其次
![](/icons/20832dou.gif)
如果参数a
![](/icons/20832de.gif)
大小装不下集合
![](/icons/20832de.gif)
所有元素
![](/icons/20832dou.gif)
返回
![](/icons/20832de.gif)
将是
![](/icons/20832yi.gif)
个新
![](/icons/20832de.gif)
![](/icons/20832shuzu.gif)
![](/icons/20832dou2.gif)
如果参数a
![](/icons/20832de.gif)
大小能装下集合
![](/icons/20832de.gif)
所有元素
![](/icons/20832dou.gif)
则返回
![](/icons/20832de.gif)
还是a
![](/icons/20832dou.gif)
但a
![](/icons/20832de.gif)
内容用集合
![](/icons/20832de.gif)
元素来填充
![](/icons/20832dou2.gif)
尤其要注意
![](/icons/20832de.gif)
是
![](/icons/20832dou.gif)
如果a
![](/icons/20832de.gif)
大小比集合元素
![](/icons/20832de.gif)
个数还多
![](/icons/20832dou.gif)
a后面
![](/icons/20832de.gif)
部分全部被置为null
![](/icons/20832dou2.gif)
最后
![](/icons/20832yi.gif)
个最重要
![](/icons/20832de.gif)
思路方法是iterator
![](/icons/20832kh.gif)
![](/icons/20832dou.gif)
返回
![](/icons/20832yi.gif)
个Iterator(迭代子)
![](/icons/20832dou.gif)
用于遍历集合
![](/icons/20832de.gif)
所有元素
![](/icons/20832dou2.gif)
用Iterator模式实现遍历集合
Iterator模式是用于遍历集合类
![](/icons/20832de.gif)
标准访问思路方法
![](/icons/20832dou2.gif)
它可以把访问逻辑从区别类型
![](/icons/20832de.gif)
集合类中抽象出来
![](/icons/20832dou.gif)
从而避免向客户端暴露集合
![](/icons/20832de.gif)
内部结构
![](/icons/20832dou2.gif)
例如
![](/icons/20832dou.gif)
如果没有使用Iterator
![](/icons/20832dou.gif)
遍历
![](/icons/20832yi.gif)
个
![](/icons/20832shuzu.gif)
![](/icons/20832de.gif)
思路方法是使用索引:
for(
![](/icons/20832int.gif)
i=0; i
而访问
![](/icons/20832yi.gif)
个链表(LinkedList)又必须使用while循环:
while((e=e.next
![](/icons/20832kh.gif)
)!=null) { ... e.data
![](/icons/20832kh.gif)
... }
以上两种思路方法客户端都必须事先知道集合
![](/icons/20832de.gif)
内部结构
![](/icons/20832dou.gif)
访问代码和集合本身是紧耦合
![](/icons/20832dou.gif)
无法将访问逻辑从集合类和客户端代码中分离出来
![](/icons/20832dou.gif)
每
![](/icons/20832yi.gif)
种集合对应
![](/icons/20832yi.gif)
种遍历思路方法
![](/icons/20832dou.gif)
客户端代码无法复用
![](/icons/20832dou2.gif)
更恐怖
![](/icons/20832de.gif)
是
![](/icons/20832dou.gif)
如果以后需要把ArrayList更换为LinkedList
![](/icons/20832dou.gif)
则原来
![](/icons/20832de.gif)
客户端代码必须全部重写
![](/icons/20832dou2.gif)
为解决以上问题
![](/icons/20832dou.gif)
Iterator模式总是用同
![](/icons/20832yi.gif)
种逻辑来遍历集合:
for(Iterator it = c.iterater
![](/icons/20832kh.gif)
; it.hasNext
![](/icons/20832kh.gif)
; ) { ... }
奥秘在于客户端自身不维护遍历集合
![](/icons/20832de.gif)
"指针"
![](/icons/20832dou.gif)
所有
![](/icons/20832de.gif)
内部状态(如当前元素位置
![](/icons/20832dou.gif)
是否有下
![](/icons/20832yi.gif)
个元素)都由Iterator来维护
![](/icons/20832dou.gif)
而这个Iterator由集合类通过工厂思路方法生成
![](/icons/20832dou.gif)
因此
![](/icons/20832dou.gif)
它知道如何遍历整个集合
![](/icons/20832dou2.gif)
客户端从不直接和集合类打交道
![](/icons/20832dou.gif)
它总是控制Iterator
![](/icons/20832dou.gif)
向它发送"向前"
![](/icons/20832dou.gif)
"向后"
![](/icons/20832dou.gif)
"取当前元素"
![](/icons/20832de.gif)
命令
![](/icons/20832dou.gif)
就可以间接遍历整个集合
![](/icons/20832dou2.gif)
首先看看java.util.Iterator接口
![](/icons/20832de.gif)
定义:
public
![](/icons/20832int.gif)
erface Iterator {
boolean hasNext
![](/icons/20832kh.gif)
;
Object next
![](/icons/20832kh.gif)
;
void remove
![](/icons/20832kh.gif)
;
}
依赖前两个思路方法就能完成遍历
![](/icons/20832dou.gif)
典型
![](/icons/20832de.gif)
代码如下:
for(Iterator it = c.iterator
![](/icons/20832kh.gif)
; it.hasNext
![](/icons/20832kh.gif)
; ) {
Object o = it.next
![](/icons/20832kh.gif)
;
// 对o
![](/icons/20832de.gif)
操作...
}
在JDK1.5中
![](/icons/20832dou.gif)
还对上面
![](/icons/20832de.gif)
代码在语法上作了简化:
// Type是具体
![](/icons/20832de.gif)
类型
![](/icons/20832dou.gif)
如String
![](/icons/20832dou2.gif)
for(Type t : c) {
// 对t
![](/icons/20832de.gif)
操作...
}
每
![](/icons/20832yi.gif)
种集合类返回
![](/icons/20832de.gif)
Iterator具体类型可能区别
![](/icons/20832dou.gif)
Array可能返回ArrayIterator
![](/icons/20832dou.gif)
Set可能返回SetIterator
![](/icons/20832dou.gif)
Tree可能返回TreeIterator
![](/icons/20832dou.gif)
但是它们都实现了Iterator接口
![](/icons/20832dou.gif)
因此
![](/icons/20832dou.gif)
客户端不关心到底是哪种Iterator
![](/icons/20832dou.gif)
它只需要获得这个Iterator接口即可
![](/icons/20832dou.gif)
这就是面向对象
![](/icons/20832de.gif)
威力
![](/icons/20832dou2.gif)
Iterator源码剖析
让我们来看看AbstracyList如何创建Iterator
![](/icons/20832dou2.gif)
首先AbstractList定义了
![](/icons/20832yi.gif)
个内部类(inner
![](/icons/20832class.gif)
):
private
![](/icons/20832class.gif)
Itr implements Iterator {
...
}
而iterator
![](/icons/20832kh.gif)
思路方法
![](/icons/20832de.gif)
定义是:
public Iterator iterator
![](/icons/20832kh.gif)
{
![](/icons/20832new.gif)
Itr
![](/icons/20832kh.gif)
;
}
因此客户端不知道它通过Iterator it = a.iterator
![](/icons/20832kh.gif)
;所获得
![](/icons/20832de.gif)
Iterator
![](/icons/20832de.gif)
真正类型
![](/icons/20832dou2.gif)
现在我们关心
![](/icons/20832de.gif)
是这个申明为private
![](/icons/20832de.gif)
Itr类是如何实现遍历AbstractList
![](/icons/20832de.gif)
:
private
![](/icons/20832class.gif)
Itr implements Iterator {
![](/icons/20832int.gif)
cursor = 0;
![](/icons/20832int.gif)
lastRet = -1;
![](/icons/20832int.gif)
expectedModCount = modCount;
}
Itr类依靠3个
![](/icons/20832int.gif)
变量(还有
![](/icons/20832yi.gif)
个隐含
![](/icons/20832de.gif)
AbstractList
![](/icons/20832de.gif)
引用)来实现遍历
![](/icons/20832dou.gif)
cursor是下
![](/icons/20832yi.gif)
次next
![](/icons/20832kh.gif)
![](/icons/20832diaoyong.gif)
时元素
![](/icons/20832de.gif)
位置
![](/icons/20832dou.gif)
第
![](/icons/20832yi.gif)
次
![](/icons/20832diaoyong.gif)
next
![](/icons/20832kh.gif)
将返回索引为0
![](/icons/20832de.gif)
元素
![](/icons/20832dou2.gif)
lastRet记录上
![](/icons/20832yi.gif)
次游标所在位置
![](/icons/20832dou.gif)
因此它总是比cursor少1
![](/icons/20832dou2.gif)
变量cursor和集合
![](/icons/20832de.gif)
元素个数决定hasNext
![](/icons/20832kh.gif)
:
public boolean hasNext
![](/icons/20832kh.gif)
{
![](/icons/20832return.gif)
cursor != size
![](/icons/20832kh.gif)
;
}
思路方法next
![](/icons/20832kh.gif)
返回
![](/icons/20832de.gif)
是索引为cursor
![](/icons/20832de.gif)
元素
![](/icons/20832dou.gif)
然后修改cursor和lastRet
![](/icons/20832de.gif)
值:
public Object next
![](/icons/20832kh.gif)
{
checkForComod
![](/icons/20832if.gif)
ication
![](/icons/20832kh.gif)
;
try {
Object next = get(cursor);
lastRet = cursor
![](/icons/20832jiajia.gif)
;
![](/icons/20832return.gif)
next;
} catch(IndexOutOfBoundsException e) {
checkForComod
![](/icons/20832if.gif)
ication
![](/icons/20832kh.gif)
;
throw
![](/icons/20832new.gif)
NoSuchElementException
![](/icons/20832kh.gif)
;
}
}
expectedModCount表示期待
![](/icons/20832de.gif)
modCount值
![](/icons/20832dou.gif)
用来判断在遍历过程中集合是否被修改过
![](/icons/20832dou2.gif)
AbstractList包含
![](/icons/20832yi.gif)
个modCount变量
![](/icons/20832dou.gif)
它
![](/icons/20832de.gif)
![](/icons/20832chushi.gif)
值是0
![](/icons/20832dou.gif)
当集合每被修改
![](/icons/20832yi.gif)
次时(
![](/icons/20832diaoyong.gif)
add
![](/icons/20832dou.gif)
remove等思路方法)
![](/icons/20832dou.gif)
modCount加1
![](/icons/20832dou2.gif)
因此
![](/icons/20832dou.gif)
modCount如果不变
![](/icons/20832dou.gif)
表示集合内容未被修改
![](/icons/20832dou2.gif)
Itr
![](/icons/20832chushi.gif)
化时用expectedModCount记录集合
![](/icons/20832de.gif)
modCount变量
![](/icons/20832dou.gif)
此后在必要
![](/icons/20832de.gif)
地方它会检测modCount
![](/icons/20832de.gif)
值:
final void checkForComod
![](/icons/20832if.gif)
ication
![](/icons/20832kh.gif)
{
![](/icons/20832if.gif)
(modCount != expectedModCount)
throw
![](/icons/20832new.gif)
ConcurrentMod
![](/icons/20832if.gif)
icationException
![](/icons/20832kh.gif)
;
}
如果modCount和
![](/icons/20832yi.gif)
开始记录在expectedModeCount中
![](/icons/20832de.gif)
值不等
![](/icons/20832dou.gif)
介绍说明集合内容被修改过
![](/icons/20832dou.gif)
此时会抛出ConcurrentMod
![](/icons/20832if.gif)
icationException
![](/icons/20832dou2.gif)
这个ConcurrentMod
![](/icons/20832if.gif)
icationException是RuntimeException
![](/icons/20832dou.gif)
不要在客户端捕获它
![](/icons/20832dou2.gif)
如果发生此异常
![](/icons/20832dou.gif)
介绍说明
![](/icons/20832chengxu.gif)
代码
![](/icons/20832de.gif)
编写有问题
![](/icons/20832dou.gif)
应该仔细检查代码而不是在catch中忽略它
![](/icons/20832dou2.gif)
但是
![](/icons/20832diaoyong.gif)
Iterator自身
![](/icons/20832de.gif)
remove
![](/icons/20832kh.gif)
思路方法删除当前元素是完全没有问题
![](/icons/20832de.gif)
![](/icons/20832dou.gif)
![](/icons/20832yinwei.gif)
在这个思路方法中会自动同步expectedModCount和modCount
![](/icons/20832de.gif)
值:
public void remove
![](/icons/20832kh.gif)
{
...
AbstractList.this.remove(lastRet);
...
// 在
![](/icons/20832diaoyong.gif)
了集合
![](/icons/20832de.gif)
remove
![](/icons/20832kh.gif)
思路方法的后重新设置了expectedModCount:
expectedModCount = modCount;
...
}
要确保遍历过程顺利完成
![](/icons/20832dou.gif)
必须保证遍历过程中不更改集合
![](/icons/20832de.gif)
内容(Iterator
![](/icons/20832de.gif)
remove
![](/icons/20832kh.gif)
思路方法除外)
![](/icons/20832dou.gif)
因此
![](/icons/20832dou.gif)
确保遍历可靠
![](/icons/20832de.gif)
原则是只在
![](/icons/20832yi.gif)
个线程中使用这个集合
![](/icons/20832dou.gif)
或者在多线程中对遍历代码进行同步
![](/icons/20832dou2.gif)
最后给个完整
![](/icons/20832de.gif)
举例:
Collection c =
![](/icons/20832new.gif)
ArrayList
![](/icons/20832kh.gif)
;
c.add("abc");
c.add("xyz");
for(Iterator it = c.iterator
![](/icons/20832kh.gif)
; it.hasNext
![](/icons/20832kh.gif)
; ) {
String s = (String)it.next
![](/icons/20832kh.gif)
;
![](/icons/20832System.gif)
.out.pr
![](/icons/20832int.gif)
ln(s);
}
如果你把第
![](/icons/20832yi.gif)
行代码
![](/icons/20832de.gif)
ArrayList换成LinkedList或Vector
![](/icons/20832dou.gif)
剩下
![](/icons/20832de.gif)
代码不用改动
![](/icons/20832yi.gif)
行就能编译
![](/icons/20832dou.gif)
而且功能不变
![](/icons/20832dou.gif)
这就是针对抽象编程
![](/icons/20832de.gif)
原则:对具体类
![](/icons/20832de.gif)
依赖性最小
(责任编辑:包春林)
TAG:
java
Java