一、`iterator`接口介绍
二、为什么需要iterator接口
三、iterator接口相关接口
3.1 ListIterator
3.2 SpitIterator
四、 iterator在集合中的实现例子
4.1 iterator在ArrayList的实现
4.2 iterator在HashMap的实现
五、总结
一、iterator
接口介绍
iterator
接口,也是集合大家庭中的一员。和其他的Map
和Collection
接口不同,iterator
主要是为了方便遍历集合中的所有元素,用于迭代访问集合中的元素,相当于定义了遍历元素的规范,而另外的Map
和Collection
接口主要是定义了存储元素的规范。
还记得么?之前说的iterable
接口,有一个方法就是叫iterator()
,也是返回iterator
对象。
迭代:不断访问集合中元素的方式,取元素之前先判断是否有元素,有则取出来,没有则结束,不断循环这个过程,直到遍历完里面所有的元素。
接口定义的方法如下:
boolean hasNext(); // 是否有下一个元素
E next(); // 获取下一个元素
// 移除元素
default void remove() {
throw new UnsupportedOperationException("remove");
}
// 对剩下的所有元素进行处理,action则为处理的动作,意为要怎么处理
default void forEachRemaining(Consumer super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
但是值得注意的是,集合类的整体不是继承了iterator
接口,而是继承了iterable
接口,通过iterable
接口的方法返回iterator
的对象。值得注意的是,iterator
的remove()
方法,是迭代过程中唯一安全的修改集合的方法,为何这样说?
如果使用for循环索引的方式遍历,删除掉一个元素之后,集合的元素个数已经变化,很容易出错。例如
for(int i=0;i if(i==2){
collection.remove(i);
}
}
而iterator
的remove()
方法则不会出错,因为通过调用hasNext()
和next()
方法,对指针控制已经处理得比较完善。
二、为什么需要iterator接口
首先,我们知道iterator
接口是为了定义遍历集合的规范,也是一种抽象,把在不同集合的遍历方式抽象出来,这样遍历的时候,就不需要知道不同集合的内部结构。
为什么需要抽象?
假设没有iterator
接口,我们知道,遍历的时候只能通过索引,比如
for(int i=0;i T item = array[i];
}
这样一来,耦合程度比较高,如果使用的数据结构变了,就要换一种写法,不利于维护已有的代码。如果没有iterator
,那么客户端需要维护指针,相当于下放了权限,会造成一定程度的混乱。抽象则是把遍历功能抽取出来,交给iterator
处理,客户端处理集合的时候,交给更“专业”的它,it do it well.
三、iterator接口相关接口
3.1 ListIterator
ListIterator
继承于Iterator
接口,功能更强大,只能用于访问各种List
类型,使用List
类型的对象list
,调用listIterator()
方法可以获取到一个指向list
开头的ListIterator
从上面图片接口看,这个接口具有访问下一个元素,判断是否有下一个元素,是否有前面一个元素,判断是否有前一个元素,获取下一个元素的索引,获取上一个元素的索引,移除元素,修改元素,增加元素等功能。和普通的Iterator
不一样的是,ListIterator
的访问指针可以向前或者向后移动,也就是双向移动。
boolean hasNext(); //是否还有元素
E next(); //获取下一个元素
boolean hasPrevious(); //是否有上一个元素
E previous(); // 获取上一个元素
int nextIndex(); //获取下一个索引
int previousIndex(); //获取上一个索引
void remove(); //移除
void set(E e); //更新
void add(E e); //添加元素
测试代码如下: