-
所有的集合類(List、Set...)都實現自Collection接口,而Collection接口又繼承於Iterable接口,因此可以說所有的集合類(List、Set...)都實現了Iterable接口
-
當某個類實現Iterable接口時,我們就能稱這個類是一個 "可數" 的類,也就是可以使用
iterator()
獲取一個迭代器Iterator,然後使用這個Iterator實例去遍歷這個類,因此所有的Collection類都能夠使用迭代器Iterator來遍歷-
Iterable接口
public interface Iterable<T> { //當某個類實現Iterable接口的話,就能獲取到迭代器iterator //然後就能使用這個iterator去遍歷此類 Iterator<T> iterator(); }
-
Iterator接口
-
如果某個類實現了Iterable接口,那麼他也需要創建一個內部類去實現一個Iterator類,讓調用Iterable接口中的iterator()時,能夠獲取到一個iterator實例
public interface Iterator<E> { //是否有下一個元素 boolean hasNext(); //取得下一個元素 E next(); //刪除最後一個獲取的元素,因此調用remove()前一定得先調用一次next() void remove(); }
-
至於此Iterator接口怎麼實現,就看各個集合實現類如何定義 "下一個元素",像是ArrayList的下一個元素就是element[index+1],而HashMap的下一個元素則是hash table數組中儲存的下一個entry
-
另外可以想像Iterator像是一個遊標一樣,一開始停在最前面,然後不停的往後走(只能向後移動),且此遊標每次都是停在元素和元素的中間,當調用next時,迭代器就越過下一個元素,並返回剛剛越過的那個元素的引用
-
-
使用迭代器Iterator遍歷ArrayList
public class Main { public static void main(String[] args) { //ArrayList實現了Collection接口,因此他也實現了Iterable接口 //所以他可以使用iterator迭代器來遍歷 List<String> list = new ArrayList<>(); list.add("hello"); list.add("world"); //調用Iterable接口中的iterator()取得此ArrayList的迭代器實例 Iterator<String> its = list.iterator(); //使用Iterator接口的hasNext()、next()來遍歷此ArrayList集合實現類 while (true) { if (its.hasNext()) { String s = its.next(); System.out.println(s); } else { break; } } } }
-
-
而再進一步說,當某個類能使用迭代器Iterator來遍歷時,就能使用java提供的foreach語法糖來遍歷此類 (foreach語法糖其實就是簡化的
iterator()
)-
foreach實際上會被編譯器編譯成使用迭代器
iterator()
去遍歷集合,因此能使用foreach的,都是得實現Iterable接口的集合類Collection們,像是List、Set -
所以Map就沒有辦法直接使用foreach(因爲Map沒有實現Iterable接口),只有他的
map.entrySet()
、map.keySet()
、map.values()
這種返回一個集合類的方法,才能使用foreach
public class Main { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("hello"); list.add("world"); //原代碼,使用語法糖的foreach for (String s : list) { System.out.println(s); } //實際上會被編譯成使用iterator去遍歷 for (Iterator<String> its = list.iterator(); its.hasNext(); ) { String s = its.next(); System.out.println(s); } } }
-
-
爲什麼Iterator要額外使用內部類去實現,而不是ArrayList直接實現此接口 ?
-
如果看過Collection類的源碼(以ArrayList爲例),可以發現ArrayList類並不是由ArrayList去實現Iterator接口,而是ArrayList有一個內部類 Itr,專門去實現Iterator接口,而ArrayList的
iterator()
方法,只是去創建一個內部類ArrayList.Itr的實例而已//ArrayList不實現Iterator接口,反而是由他的內部類進行實現 public class ArrayList<E> extends AbstractList<E> { //調用list.iterator()可以取得此list的迭代器 public Iterator<E> iterator() { return new Itr(); //實際上就是去創建一個內部類的實例 } //ArrayList中的內部類Itr,專門實現Iterator接口 private class Itr implements Iterator<E> { int cursor; //記錄當前迭代到哪裡 public boolean hasNext() { ... } public E next() { ... } public void remove() { ... } } }
-
要這樣設計是因爲一個集合類可能同時有多個迭代器去遍歷他,而每個迭代器遍歷到集合的哪裡,是每個迭代器自己的事情,彼此不互相干涉,因此才需要額外使用一個內部類去實現迭代器的Iterator接口
-
如此當需要用到Iterator來遍歷集合時,只需要調用
list.iterator()
,就能取得一個全新的、不受別人影響的迭代器供自己使用,而迭代器彼此之間也不會互相干涉 -
至於爲什麼要特別使用內部類來實現Iterator接口,而不是創建一個Iterator公共類來供所有集合一起使用,是因爲迭代器需要知道集合的內部結構,他才能知道要怎麼去實現
hasNext()
、next()
、remove()
方法,而使用內部類才能無條件的取用外部類的所有信息(包含private的變量和方法),因此才需要將Iterator提取成接口,讓每個集合自己使用內部類去實現Iterator接口
-
-
Java - Iterable接口、迭代器Iterator
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.