Java容器原始碼攻堅戰--第一戰:Iterator
基於java10.1
零、前言
如果想讀讀原始碼測試功力,或讀讀原始碼修養身心,或讀讀原始碼滿足自虐傾向,我建議第一個類是:ArrayList
第一、常用----所以用法比較熟悉,看完原始碼你也會更明白如何去用
第二、相對簡單----1595行程式碼,刨去註釋的一大堆也沒有太多,還是hold的住的
第三、還沒想好
這篇並不是講ArrayList,而是Iterator,它是容器以及對映中非常重要的一環
一、迭代器模式
提起設計模式,總是有種 只知其形,難達其意
的感覺,用三個字說就是 高大上
迭代器模式(Iterator),提供一種方法順序訪問一個聚合物件中的各個元素,而又不暴露該物件的內部表示。 優勢:它支援以不同的方式遍歷一個聚合 迭代器簡化了聚合的介面 在同一個聚合上可以有多個遍歷

迭代器模式.png
1.介面卡介面
最簡單的介面卡有兩個方法hasNext()和next(),這兩個方法可以組成一個邏輯鏈:如果有下一個,取出下一個
/** * 作者:張風捷特烈 * 時間:2018/10/1 0001:23:11 * 郵箱:[email protected] * 說明:介面卡介面 */ public interface Iterator<T> { /** * 是否有下一個元素 * @return 是否有下一個元素 */ boolean hasNext(); /** * 下一個元素 * @return 下一個元素 */ T next(); }
2.聚合物件介面
所謂聚合就是內部含有多個某型別的元素,比如教室和學生的關係,就是聚合物件(教室)與單體元素(學生)的關係
/** * 作者:張風捷特烈 * 時間:2018/10/1 0001:23:17 * 郵箱:[email protected] * 說明:聚合物件介面 */ public interface Group<T> { /** * 新增元素 * @param el 元素 */ void add(T el); /** * 獲取元素 * @param index 索引 * @return 元素 */ T get(int index); /** * 獲取迭代器 * @return 迭代器 */ Iterator<T> iterator(); /** * 內部元素總數 * @return 元素總數 */ int size(); }
3.迭代器實現類
/** * 作者:張風捷特烈 * 時間:2018/10/1 0001:23:13 * 郵箱:[email protected] * 說明:迭代器實現類 */ public class IteratorImpl<T> implements Iterator { //持有聚合物件引用 private Group<T> mGroup; //當前遊標指向的索引處 private int curIndex; public IteratorImpl(Group group) { mGroup = group; } @Override public boolean hasNext() { //當遊標的指向索引比元素總數少,說明還有next return curIndex < mGroup.size(); } @Override public T next() { //返回當前索引處元素 T el = mGroup.get(curIndex); //當遊標的指向索引後移 curIndex++; return el; } }
4.集合物件實現類
/** * 作者:張風捷特烈 * 時間:2018/10/1 0001:23:20 * 郵箱:[email protected] * 說明:集合物件實現類 */ public class GroupImpl<T> implements Group<T> { //維護一個數組盛放元素 private T[] data; //維護內部元素個數 private int size = 0; public GroupImpl() { //為了簡單,使用固定容積50 data = (T[]) new Object[50]; } @Override public void add(T el) { data[size] = el; size++; } @Override public T get(int index) { return data[index]; } @Override public Iterator<T> iterator() { return new IteratorImpl(this); } @Override public int size() { return size; } }
5.測試
public class Client { public static void main(String[] args) { GroupImpl<Student> classRoom = new GroupImpl<>(); classRoom.add(new Student(1, "捷特")); classRoom.add(new Student(2, "龍少")); classRoom.add(new Student(3, "巫纓")); for (int i = 0; i < classRoom.size(); i++) { System.out.println(classRoom.get(i)); } Iterator<Student> it = classRoom.iterator(); //System.out.println(it.next());//Student{id=1, name='捷特'} //System.out.println(it.next());//Student{id=2, name='龍少'} //System.out.println(it.next());//Student{id=3, name='巫纓'} //System.out.println(it.next());//null while (it.hasNext()) { System.out.println(it.next()); //Student{id=1, name='捷特'} //Student{id=2, name='龍少'} //Student{id=3, name='巫纓'} } } }

迭代器模式例.png
二、ArrayList中的Iterator
java中內建的聚合類,頂尖介面Collection實現了Iterable介面,也就是可迭代
1.Iterable介面中定義了獲取Iterator物件的函式iterator()
public interface Iterable<T> { Iterator<T> iterator();
2.Collection繼承了Iterable介面也必然繼承它的方法
public interface Collection<E> extends Iterable<E> { Iterator<E> iterator();
3.同樣List介面繼承了Collection介面也必然這個方法
public interface List<E> extends Collection<E> { Iterator<E> iterator();
4.java中自帶的迭代器:Iterator
public interface Iterator<E> { //是否擁有下一個元素 boolean hasNext(); //下一個元素 E next(); default void remove() { throw new UnsupportedOperationException("remove"); } default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); } }
4.該方法在ArrayList中的實現
private class Itr implements Iterator<E>
說明該迭代器實現類Itr是ArrayList的內部類
這樣做就不必讓Itr持有ArrayList的引用,簡單一些。
public Iterator<E> iterator() { //返回一個迭代器實現類物件 return new Itr(); } private class Itr implements Iterator<E> { int cursor;// 遊標:將要返回的元素索引 int lastRet = -1; // 最後一個被返回元素的索引,-1表示沒有返回過 int expectedModCount = modCount;//期望的修改次數與真是修改次數置同 //私有化構造方法 Itr() {} public boolean hasNext() { //當遊標未達到元素總數時,表明還有下一個元素 return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification();//見I--1 int i = cursor;//用變數i暫存遊標位置 if (i >= size)//遊標位置大於等於size,丟擲異常 throw new NoSuchElementException(); //獲取當前ArrayList的成員變數:elementData(當前陣列) Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length)//遊標位置大於當前陣列總長,丟擲異常 throw new ConcurrentModificationException(); cursor = i + 1;//遊標後移 //維護lastRet為i,即返回的元素索引 return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0)//即沒有呼叫過next()方法:見Test-1 throw new IllegalStateException(); checkForComodification();//見I--1 try { ArrayList.this.remove(lastRet);//移除操作 cursor = lastRet;//索引指向剛才移除的索引位 lastRet = -1;//最後返回的索引置為-1,[由此可見不能連續執行兩次iterator.remove()操作] expectedModCount = modCount;//期望的修改次數與真是修改次數置同 } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } @Override//測試見:Test-2 public void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action);//判斷是否為空,空則拋空指標 final int size = ArrayList.this.size;//size記錄元素中個數 int i = cursor;//用變數i暫存遊標位置 if (i < size) { final Object[] es = elementData;//記錄陣列 if (i >= es.length)//越界 throw new ConcurrentModificationException(); for (; i < size && modCount == expectedModCount; i++) action.accept(elementAt(es, i));//見I--2 // update once at end to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification();///見I--1 } } }
I--1:檢視期望修改次數與實際修改次數是否相同
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
I--2:返回一個數組指定索引位置的元素
static <E> E elementAt(Object[] es, int index) { return (E) es[index]; }
Test-1
ArrayList<String> aList = new ArrayList(); aList.add("b"); aList.add("a"); aList.add("c"); Iterator<String> iterator = aList.iterator(); iterator.remove();//直接使用移除會報異常 //Exception in thread "main" java.lang.IllegalStateException
ArrayList<String> aList = new ArrayList(); aList.add("b"); aList.add("a"); aList.add("c"); Iterator<String> iterator = aList.iterator(); String first = iterator.next(); System.out.println(first);//b System.out.println(aList);//[b, a, c] //執行過iterator.next(),lastRet指向返回元素的位置,就不再是0,呼叫remove就不會異常了 iterator.remove();//移除iterator最後返回的元素 System.out.println(aList);//[a, c]
Iterator<String> iterator = aList.iterator(); String first = iterator.next(); String second = iterator.next(); System.out.println(first);//b System.out.println(second);//a System.out.println(aList);//[b, a, c] //執行兩次iterator.next(),iterator最後返回的元素為a,移除之 iterator.remove(); System.out.println(aList);//[b, c]
Test-2
ArrayList<String> aList = new ArrayList(); aList.add("b"); aList.add("a"); aList.add("c"); Iterator<String> iterator = aList.iterator(); iterator.forEachRemaining(s -> { s += "-Hello"; System.out.print(s+" ");//b-Hello a-Hello c-Hello });
就醬紫,Iterator這個類的用法差不多也就這些
後記:捷文規範
1.本文成長記錄及勘誤表
專案原始碼 | 日期 | 備註 |
---|---|---|
V0.1--無 | 2018-10-2 | ofollow,noindex">Java容器原始碼攻堅戰--第一戰:Iterator |
V0.2--無 | - | - |
2.更多關於我
筆名 | 微信 | 愛好 | |
---|---|---|---|
張風捷特烈 | 1981462002 | zdl1994328 | 語言 |
我的github | 我的簡書 | 我的CSDN | 個人網站 |
3.宣告
1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大程式設計愛好者共同交流
3---個人能力有限,如有不正之處歡迎大家批評指證,必定虛心改正
4----看到這裡,我在此感謝你的喜歡與支援