前兩天,一哥們拿着同一個問題連續找了我兩次。一開始覺得沒什麼說的東西,後來越研究越以爲有意思,今天閒來無事,寫出來跟你們分享。java
問題是這樣的:「迭代集合時,Iterator it=c.iterator() 返回的到底接口Iterator的哪一個實現類?」。剛開始我隨口就是「查查API不就知道了麼」,後來證實查API還真就「不知道」。API顯示Iterator只有三個實現類(BeanContextSupport.BCSIterator, EventReaderDelegate, Scanner),可是哪個都不像是跟迭代有關的。後來查源碼,發現Iterator設計和實現的精妙之處。編程
jdk源碼 Iterator接口定義以下:設計模式
public interface Iterator<E> { boolean hasNext();//判斷容器內是否還有可供訪問的元素 E next();//返回迭代器剛越過的元素的引用,返回值是Object,須要強制轉換成本身須要的類型 void remove();//刪除迭代器剛越過的元素 }
咱們都知道,其實在編程過程當中常用的,也只有hasNext()和next()。通常咱們都是這麼進行迭代:數組
Iterator it=c.iterator(); while(it.hasNext()){ Object o=it.next(); //do something }
不難發現,不管迭代的是List集合仍是Set集合,也不管集合底層是採用數組實現的ArrayList、Vector、HashSet,或者是採用鏈表實現的LinkedList、又或者是採用二叉樹實現的TreeSet,通通都是經過統一的方法hasNext()、next()來判斷、獲取下一個元素,可是具體的內部操做確定是不同的,那Iterator是怎麼作到的呢?其實,並非Iterator怎麼作到,而是每個集合類本身分別來進行實現的。下面我以ArrayList爲例,跟你們一塊兒分析一下jdk的精妙實現:ide
衆所周知,ArrayList的內部實現採用數組,因此咱們只須要記錄相應位置的索引就能夠了,其方法的實現也是比較簡單的。它經過定義內部類內部類,來實現Iterator接口來實現的,以下:this
private class Itr implements Iterator<E> { int cursor = 0;//cursor從0開始,表示下一個元素的索引位置 int lastRet = -1;//lastRet從-1開始,表示上一個元素的索引位置 int expectedModCount = modCount;//記錄對集合修改的次數,主要是用於實現ArrayList集合的快速失敗機制 /** *hasNext()只需判斷當前位置是否是處在最後一個了便可. */ public boolean hasNext() { return cursor != size(); } /** * next()實現其實也是比較簡單的,只要返回cursor索引位置處的元素便可,而後修改cursor、lastRet便可. */ public E next() { checkForComodification();//主要用來判斷集合的修改次數是否合法,即用來判斷遍歷過程當中集合是否被修改過. try { E next = get(cursor);//從底層實現數組裏取得當前元素 lastRet = cursor++;//lastRet+1 return next;//返回當前元素 } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } /** * 調用ArrayList自己的remove()方法刪除lastRet位置元素,而後修改modCount便可. */ public void remove() { if (lastRet == -1) throw new IllegalStateException(); checkForComodification(); try { AbstractList.this.remove(lastRet);//從底層實現數組裏刪除上一個元素 if (lastRet < cursor) cursor--;//因爲當前元素要填補到上一個元素的位置去,因此當前元素下標-1 lastRet = -1; expectedModCount = modCount;//把集合的修改次數賦值給expectedModCount } catch (IndexOutOfBoundsException e) { throw new ConcurrentModificationException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
這就是ArrayList的Iterator接口的實現。有人會問「那豈不是每個集合類都要提供對Iterator的實現啊?」,對!Iterator只提供方法,你要想使用其進行迭代遍歷,就必須提供對它的迭代實現。實際上,LinkedList、Vector、HashSet、TreeSet等集合的Iterator實現也都採用相似的設計思路。設計
經過以上探究,咱們不難看出,Iterator給咱們提供了一種通用的遍歷各類集合的方法,它能夠把訪問邏輯從不一樣類型的集合類中抽象出來,作到了訪問代碼和集合自己的解耦,從而避免向客戶端暴露集合的內部結構。今後,客戶端能夠不直接和集合類打交道,它只須要控制Iterator,向它發送「向前」、「向後」、「取當前元素」、「刪元素」的命令,就能夠間接遍歷和操做整個集合,而且這些客戶端代碼仍是能夠複用的。其實,這就是java中很是著名的Iterator設計模式。索引
書到用時方恨少,事非通過不知難。點滴積累,你就會成爲技術上的巨人!接口