Java容器类源码分析之Iterator与ListIterator迭代器(基于JDK8)
一、基本概念
迭代器是一个对象,也是一种设计模式,java有两个用来实实现迭代器的接口,分别是iterator接口和继承自iterator的listiterator接口。实现迭代器接口的类的对象有遍历集合对象,选择集合中的元素和删除集合中元素的方法。而在使用它时不必知道该集合对象底层的结构。java类库中实现iterator接口的迭代器只能正向遍历集合中的元素,而实现listiterator接口的迭代器不仅能够正向遍历,还能够反向遍历集合中的元素。
二、源码分析
2.1、iterator接口与listiterator接口的继承与实现
图2.1 java迭代器类的继承与接口实现(部分)
listiterator接口继承了iterator接口。在abstractlist、arraylist和vector这三个类中的内部类listitr实现了listiterator接口,这三个类的内部类listitr又分别继承了在这三个类中实现了iterator接口的内部类itr。实现listiterator的类还有linkedlist的内部类listitr。实现iterator的类还有linkedlist的内部类descendingiterator,hashmap的内部类entryiterator,keyiterator,valueiterator,以及treemap的内部类privateentryiterator等。
2.2、迭代器接口方法
1)迭代器的向前移动与向后移动图解
2)iterator接口方法
package java.util; import java.util.function.consumer; public interface iterator<e> { boolean hasnext(); /* 在java中,这个方法的具体实现一般用来在遍历容器时,调用该方法使迭代器向前移动一位,来检测集合中是否还有下一个元素,还有下一个元素返回true,否则返回false*/ e next(); /* 实现这个方法,在遍历容器时,调用该方法将迭代器向前移动一位,并将迭代器越过的一个元素作为方法的返回值。该方法用来返回集合中下一个元素。
在调用next()方法前,先调用hasnext()方法判断集合中是否还有下一个元素 */
default void remove() { throw new unsupportedoperationexception("remove"); }
/* 实现这个方法,用来删除在迭代器调用next()方法迭代器越过的一个元素*/
default void foreachremaining(consumer<? super e> action) { objects.requirenonnull(action); while (hasnext()) action.accept(next()); }
/* 实现这个方法来顺序遍历容器中的每个元素,用来实现集合类的foreach遍历操作*/
}
3)listiterator接口方法
package java.util; public interface listiterator<e> extends iterator<e> { boolean hasnext();//同iterator接口,用来检测迭代器前面是否还有元素 e next();
// 同iterator接口,使迭代器向前移动一位,获得迭代器越过的下一个元素 boolean hasprevious();
// 实现这个方法来检测当前迭代器位置后面是否有元素,用于反向遍历 e previous(); /* 实现这个方法,将迭代器向后移动一位,并将迭代器越过的后面的一个元素作为方法返回值,在调用该方法前需要调用hasprevious方法来判断迭代器前是否有元素 */ int nextindex();//实现该方法获取迭代器前面一个元素的索引 int previousindex();//实现该方法获取迭代器后面一个元素的索引 void remove(); /* 实现该方法,用来删除迭代器调用next()方法或调用previous()方法时迭代器越过的一个元素 */ void set(e e);//实现该方法在迭代器遍历时修改元素 void add(e e);//实现该方法在迭代器遍历时添加元素 }
2.3、集合类与迭代器的关系
1)iterator接口。阅读源码可知,collectiion接口实现了iterable接口,iterable有一个返回一个iterator<t>对象的iterator()方法,所以继承和实现了collection接口的所有容器类及其子类和实现类都有一个返回iterator对象的的iterator()方法。java中有很多集合类中都设计有实现了iterator接口的内部类,如arraylist和linkedlist等类。hashmap和treemap类中也包含有实现了iterator的内部类,来对map中的keyset、value和entryset进行迭代。iterable接口的源代码如下:
public interface iterable<t> { iterator<t> iterator();//实现这个方法,该方法返回一个iterator迭代器对象。
default void foreach(consumer<? super t> action) { objects.requirenonnull(action); for (t t : this) { action.accept(t); } }//实现这个方法来对容器进行foreach遍历 default spliterator<t> spliterator() { return spliterators.spliteratorunknownsize(iterator(), 0); } }
2)listiterator接口。查看源码可以发现,list接口中有两个返回listiterator<t>对象的方法,如下。list接口下的的arraylist和linkedlist都有返回listiterator对象的方法。
listiterator<e> listiterator();//实现这个方法,该方法返回一个listiterator迭代器对象,迭代器初始化后,一般迭代器位于在容器第一个元素后面。 listiterator<e> listiterator(int index);//实现这个方法,返回一个指定了开始遍历容器时迭代器初始位置的listiterator迭代器对象
- arraylist类设计有实现了listiterator接口的内部类listitr(不过arraylist的listiterator(final int index)方法并未使用这个内部类,而是在方法中又设计了一个listiterator匿名内部类作为方法返回值,可以发现arraylist的iterator()方法也是调用了这个方法来构建迭代器对象)。arraylist类中部分有关源码如下
private class listitr extends itr implements listiterator<e> { listitr(int index) { super(); cursor = index; }
public iterator<e> iterator() { return listiterator(); } public listiterator<e> listiterator(final int index) { checkforcomodification(); rangecheckforadd(index); final int offset = this.offset; return new listiterator<e>() {//返回了一个listiterator内部类 int cursor = index; int lastret = -1; int expectedmodcount = arraylist.this.modcount; public boolean hasnext() { return cursor != sublist.this.size; }
- linkedlist类也有内部类listitr实现了listiterator接口,linkedlist的listiterator()方法返回了这个内部类的实例。linkedlist中部分有关源码如下
public listiterator<e> listiterator(int index) { checkpositionindex(index); return new listitr(index); } private class listitr implements listiterator<e> {
(小官原创,若有谬误,望各位前辈批评指正)
上一篇: php生成zip压缩文件的方法详解
下一篇: 【深度】自媒体创业泡沫消亡史