三、Iterator–容器中的特殊遍历
- 所有实现了Collection接口的容器类都有一个iterator方法用以返回一个实现了Iterator接口的对象;
- 作用:Iterator对象作为迭代器,是用来实现遍历操作的;
- Iterator接口定义的方法:
Iterator it = Collection集合对象.iterator();// 获得迭代器
boolean hashNext();// 判断是否有元素没有被遍历
Object next();//返回游标当前位置的元素并将游标移动到下一个位置
void remove();// 删除游标左面的元素,remove()必须紧跟在next()方法后执行,在每次调用next()时,remove方法只能被调用一次。
4 . 分析
Iterator iterator();定义一个引用类型(接口类型)的变量it来“接收”返回的Iterator
A.Iterator仅用于遍历集合,其本身并不能提供盛装对象的能力
B. List和Set都有iterator()来取得其迭代器。对List来说,你也可以通过listIterator()取得其迭代器,两种迭代器在有些时候是不能通用的,Iterator和ListIterator主要区别在以下方面:
a. ListIterator有add()方法,可以向List中添加对象,而Iterator不能
b. ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是 ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
c.ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
d. 都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。
public class TestIterator {
public static void main(String[] args) {
List list = new ArrayList();
list.add("aaa");
list.add("bbb");
list.add("ccc");
for (int i = 0; i < list.size(); i ++){
System.out.println((String)list.get(i));
}
Set set = new HashSet();
set.add("1");
set.add("2");
set.add("3");
// 迭代器iterator遍历set
Iterator ite = set.iterator();// iterator迭代器:Iterator it = 实现Collectio接口的对象.iterator;
while (ite.hasNext()){
System.out.println((String)ite.next());
// ite.remove();
}
}
}
public class TestListIterator {
public static void main(String[] args) {
List list = new ArrayList();
list.add("aa");
list.add("bb");
list.add("cc");
list.add("dd");
ListIterator it = list.listIterator(list.size());
while (it.hasPrevious()){// 逆向遍历
it.previous();
}
}
}
5 .关于Java中的增强for循环
增强for的效率高,是因为直接操作硬盘,实际也是迭代器。区别是增强for没有删除,迭代器有,而且是在查看的时候就可以删除。
MyArrayList:
/**
* 深入理解迭代器原理
* 模拟迭代器的三个常用方法
* @author Fanff
*
*/
public class MyArrayList {
private String[] elem = {"a", "b", "c", "d", "e", "f", "g"};
private int size = elem.length;
private int cursor = 0;// 游标,ArrayList中是置为的0,其他有些地方是-1
/**
* 判断是否还存在下一个元素
*/
public boolean hasNext(){
return cursor < size;
}
/**
* 返回游标所指的当前位置的元素,并将游标移到下一个位置
*/
public String next(){
String e = elem[cursor];
cursor++;
return e;
}
/**
* 删除游标所指位置的元素
*/
public void remove(){}
public static void main(String[] args) {
MyArrayList list = new MyArrayList();
while (list.hasNext()){
System.out.println(list.next());
}
}
}
MyArrayList1:
import java.util.Iterator;
/**
* 深入理解迭代器原理
* 自定义迭代器:实现Iterator接口
* 将迭代器中的三个常用方法封装成内部类,以减少开销
* @author Fanff
*
*/
public class MyArrayList1 {
private String[] elem = {"a", "b", "c", "d", "e", "f", "g"};
private int size = elem.length;
private class MyImpIterator implements Iterator<String>{
private int cursor = 0;// 游标,ArrayList中是置为的0,其他有些地方是-1
/**
* 判断是否还存在下一个元素
*/
public boolean hasNext(){
return cursor < size;
}
/**
* 返回游标所指的当前位置的元素,并将游标移到下一个位置
*/
public String next(){
String e = elem[cursor];
cursor++;
return e;
}
/**
* 删除游标所指位置的元素
*/
public void remove(){}
}
public Iterator<String> myIterator(){
return new MyImpIterator();
}
public static void main(String[] args) {
MyArrayList1 list = new MyArrayList1();
Iterator<String> it = list.myIterator();
while (it.hasNext()){
System.out.println(it.next());
}
// 如果要再遍历一次只需要通过myIterator()方法new一个MyImpIterator()
// 而不需要new一个MyArrayList1()对象,减小了开销
Iterator<String> it1 = list.myIterator();
while (it1.hasNext()){
System.out.println(it1.next());
}
}
}
MyArrayList2:
import java.util.Iterator;
/**
* 深入理解迭代器原理:
* 理解增强for循环的本质
*使用增强for循环,必须是遍历的数组,或者是实现了Iterable接口
* @author Fanff
*
*/
public class MyArrayList2 implements Iterable<String>{
private String[] elem = { "a", "b", "c", "d", "e", "f", "g" };
private int size = elem.length;
// 匿名内部类
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
private int cursor = 0;// 游标,ArrayList中是置为的0,其他有些地方是-1
/**
* 判断是否还存在下一个元素
*/
public boolean hasNext() {
return cursor < size;
}
/**
* 返回游标所指的当前位置的元素,并将游标移到下一个位置
*/
public String next() {
String e = elem[cursor];
cursor++;
return e;
}
/**
* 删除游标所指位置的元素
*/
public void remove() {
}
};
}
public static void main(String[] args) {
MyArrayList2 list = new MyArrayList2();
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println("-----增强for循环的效率更高是因为实际上其是利用的迭代器-----");
// 使用增强for循环,必须是遍历的数组,货值是实现了Iterable接口
for (String temp : list){
System.out.println(temp);
}
}
}
说明:
(1). 查看jdk可知Iterable和Iterator都是接口,但Iterable中只有一个返回Iterator对象的方法;
(2). Iterable和Iterator的区别(http://blog.csdn.net/ningguixin/article/details/8079242):
很多类(尤其是一些集合类)都实现了Iterable接口,这样就可以通过实现Iterable接口里唯一的的方法Iterator iterator();返回一个Iterator对象,进而实现Itrator接口中的三个常用方法,从而调用这三个常用方法。HashSet类就实现了Iterable接口,而要访问或打印出Set中所有内容时,就是利用的Iterator对象(实例如下)【Iterator it = 实现Collectio接口的对象.iterator;】
(3). 为什么一定要实现Iterable接口,为什么不直接实现Iterator接口呢?
JDK中的集合类,比如List一族或者Set一族,都是实现了Iterable接口,但并不直接实现Iterator接口。
原因: 因为Iterator接口的核心方法next()或者hasNext() 是依赖于迭代器的当前迭代位置的。如果Collection直接实现Iterator接口,那么势必导致集合对象中包含当前迭代位置的数据(指针)。当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。
但即时这样,Collection也只能同时存在一个当前迭代位置。 而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。 多个迭代器是互不干扰的。