創建包com.tenth.iterator,在包下創建Demo13.java
Java的集合類都可以使用for…each循環,List、Set和Queue會迭代每個元素,Map會迭代每個Key。以List爲例:
List<String> list = List.of("Apple", "Orange", "Pear");
for (String s : list) {
System.out.println(s);
}
實際上,Java編譯器並不知道如何遍歷List。上述代碼能夠編譯通過,只是因爲編譯器把for each循環通過Iterator改寫爲了普通的for循環:
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
String s = it.next();
System.out.println(s);
}
我們把這種通過Iterator對象遍歷集合的模式稱爲迭代器。
使用迭代器的好處在於,調用方總是以統一的方式遍歷各種集合類型,而不必關係它們內部的存儲結構。
例如,我們雖然知道ArrayList在內部是以數組形式存儲元素,並且,它還提供了get(int)方法。雖然我們可以用for循環遍歷:
for (int i=0; i<list.size(); i++) {
Object value = list.get(i);
}
但是這樣一來,調用方就必須知道集合的內部存儲結構。並且,如果把ArrayList換成LinkedList,get(int)方法耗時會隨着index的增加而增加。如果把ArrayList換成Set,上述代碼就無法編譯,因爲Set內部沒有索引。
用Iterator遍歷就沒有上述問題,因爲Iterator對象是集合對象自己在內部創建的,它自己知道如何高效遍歷內部的數據集合,調用方則獲得了統一的代碼,編譯器才能把標準的for each循環自動轉換爲Iterator遍歷。
如果我們自己編寫了一個集合類,想要使用for each循環,只需滿足以下條件:
- 集合類實現Iterable接口,該接口要求返回一個Iterator對象;
- 用Iterator對象迭代集合內部數據。
這裏的關鍵在於,集合類通過調用iterator()方法,返回一個Iterator對象,這個對象必須自己知道如何遍歷該集合。
一個簡單的Iterator示例如下,它總是以倒序遍歷集合:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Demo13 {
public static void main(String[] args) {
ReverseList<String> rlist = new ReverseList<>();
rlist.add("Apple");
rlist.add("Orange");
rlist.add("Pear");
for (String s : rlist) {
System.out.println(s);
}
}
}
class ReverseList<T> implements Iterable<T> {
private List<T> list = new ArrayList<>();
public void add(T t) {
list.add(t);
}
@Override
public Iterator<T> iterator() {
return new ReverseIterator(list.size());
}
class ReverseIterator implements Iterator<T> {
int index;
ReverseIterator(int index) {
this.index = index;
}
@Override
public boolean hasNext() {
return index > 0;
}
@Override
public T next() {
index--;
return ReverseList.this.list.get(index);
}
}
}
雖然ReverseList和ReverseIterator的實現類稍微比較複雜,但是,注意到這是底層集合庫,只需編寫一次。而調用方則完全按for each循環編寫代碼,根本不需要知道集合內部的存儲邏輯和遍歷邏輯。
在編寫Iterator的時候,我們通常可以用一個內部類來實現Iterator接口,這個內部類可以直接訪問對應的外部類的所有字段和方法。例如,上述代碼中,內部類ReverseIterator可以用ReverseList.this獲得當前外部類的this引用,然後,通過這個this引用就可以訪問ReverseList的所有字段和方法。
小結
Iterator是一種抽象的數據訪問模型。使用Iterator模式進行迭代的好處有:
- 對任何集合都採用同一種訪問模型;
- 調用者對集合內部結構一無所知;
- 集合類返回的Iterator對象知道如何迭代。
Java提供了標準的迭代器模型,即集合類實現java.util.Iterable接口,返回java.util.Iterator實例。
謝謝觀看