前言: Iterator翻譯過來就是迭代器的意思。在前面的工廠模式中就介紹過了iterator,不過當時介紹的是方法,現在從Iterator介面的設計來看,似乎又是一種設計模式,下麵我們就來講講迭代器模式到底是怎麼實現的。 一、定義 提供一種方法,順序訪問一個集合對象中的各個元素,而又不暴露該對象的 ...
前言:
Iterator翻譯過來就是迭代器的意思。在前面的工廠模式中就介紹過了iterator,不過當時介紹的是方法,現在從Iterator介面的設計來看,似乎又是一種設計模式,下麵我們就來講講迭代器模式到底是怎麼實現的。
一、定義
提供一種方法,順序訪問一個集合對象中的各個元素,而又不暴露該對象的內部表示。(可以理解為遍歷)
二、適用場景
1、訪問一個集合對象的內容而無需暴露它的內部表示
2、為遍歷不同的集合結構提供一個統一的介面
重要的是對第二點的理解,前面我們在工廠方法中講過iterator是個工廠方法,Iterator是個產品總介面。對於我們需要的是Iterator這個產品,產品的功能是遍歷,我們並不關心這個產品裡面存儲的結構是List還是Map,不同存儲結構的遍歷實現應該交給下麵的不同的工廠去實現。這裡同樣也可以這麼理解。但是,我們今天講的是迭代器模式。工廠模式是創建型,而這個模式是行為型。在這裡我們或許可以先拋開工廠模式,來去理解這個迭代器模式。
三、結合Iterator介面看迭代器
迭代器模式的角色構成
1、迭代器(Iterator):定義訪問和遍歷元素的介面。
2、具體迭代器(ConcreteIterator ):具體迭代器,實現了迭代器介面,內部會具體實現如何遍歷當前聚合。
3、聚合(Aggregate):內部創建相應迭代器介面的方法。
4、具體聚合(ConcreteAggregate):內部具體有存儲方式以及實現相應迭代器介面,以及一些操作。
下麵我們來結合源碼來理解上面4個角色具體是什麼樣的:
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()); } }
上面是迭代器Iterator介面的代碼,定義了一些需要子類實現的方法和預設的方法。在這裡說一下上面兩個default方法都是JDK1.8之後才有的介面新特性,在JDK1.8之前介面中不能有方法實體。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } @Override @SuppressWarnings("unchecked") public void forEachRemaining(Consumer<? super E> consumer) { Objects.requireNonNull(consumer); final int size = ArrayList.this.size; int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } while (i != size && modCount == expectedModCount) { consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } } }
上面是簡化的ArrayList類,因為具體實現迭代器Itr的類在ArrayList中作為內部類存在,這個內部類將介面中的方法做了具體實現,並且是只對ArrayList這個類進行實現的。
public interface List<E> extends Collection<E> { Iterator<E> iterator(); }
上面是簡化的List介面,充當的是聚合介面,可以看見內部創建了相應迭代器介面的方法。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { public Iterator<E> iterator() { return new Itr(); } }
上面是簡化的ArrayList類,充當的是具體聚合類角色,在這裡是直接返回了一個具體實現迭代器的類。
public class Test1 { public static void main(String[] args) { List<Integer> a=new ArrayList<>(); a.add(1); a.add(2); a.add(3); while(a.iterator().hasNext()){ System.out.println(a.iterator().next()); } } }
這是一個錯誤的測試類,因為我們每調用一次iterator方法都是會new一個Itr對象,也就是裡面的游標會一直重置為0,所以會無限迴圈。下麵才是正確的測試方法
public class Test1 { public static void main(String[] args) { List<Integer> a=new ArrayList<>(); a.add(1); a.add(2); a.add(3); Iterator Itr=a.iterator(); while(Itr.hasNext()){ System.out.println(Itr.next()); } } }
四、總結
平常寫代碼的時候總會有使用iterator。但是如果要我們自己去動手實現一個集合類的會很少,除非是寫框架的時候,大多數我們還是使用為主。當我們需要使用迭代器模式的時候,只需要看上面4個源碼的角色扮演和分析,很快就能寫出自己的迭代器。前面在適用場景的時候我們是用工廠方法模式來去理解Iterator,但學完這個模式之後,以後的Iterator介面下的實現類,你都可以認為是迭代器模式。因為迭代器模式在各種集合對象中用的實在是太廣泛了,所以專門拿這個模式進行源碼解釋。