Wir verwenden häufig die von JDK bereitgestellte Iterationsschnittstelle, um Java-Sammlungen zu iterieren.
Iterator iterator = list.iterator(); while(iterator.hasNext()){ String string = iterator.next(); //do something }
Tatsächlich können wir Iteration einfach als Traversierung verstehen, eine standardisierte Methodenklasse zum Durchlaufen aller Objekte in verschiedenen Containern. Es handelt sich um ein sehr typisches Entwurfsmuster. Das Iterator-Muster ist die Standardzugriffsmethode zum Durchlaufen von Sammlungsklassen. Es kann die Zugriffslogik von verschiedenen Arten von Sammlungsklassen abstrahieren und so vermeiden, dass die interne Struktur der Sammlung dem Client offengelegt wird. So machen wir es, wenn keine Iteratoren vorhanden sind. Wie folgt:
Für Arrays verwenden wir Indizes zur Verarbeitung:
int[] arrays = new int[10]; for(int i = 0 ; i < arrays.length ; i++){ int a = arrays[i]; //do something }
Für ArrayList verarbeiten wir es folgendermaßen:
List<String> list = new ArrayList<String>(); for(int i = 0 ; i < list.size() ; i++){ String string = list.get(i); //do something }
Bei beiden Methoden kennen wir die interne Struktur der Sammlung immer im Voraus. Der Zugriffscode und die Sammlung selbst sind eng miteinander verbunden, und die Zugriffslogik kann nicht von der Sammlungsklasse und dem Clientcode getrennt werden . herauskommen. Gleichzeitig entspricht jede Sammlung einer Traversierungsmethode und der Clientcode kann nicht wiederverwendet werden. In praktischen Anwendungen ist es ziemlich mühsam, die beiden oben genannten Sätze zu integrieren. Um die oben genannten Probleme zu lösen, wurde der Iterator-Modus entwickelt, der immer dieselbe Logik zum Durchlaufen der Sammlung verwendet. Dadurch entfällt die Notwendigkeit, dass der Client selbst die interne Struktur der Sammlung verwaltet, und alle internen Zustände werden von Iterator verwaltet. Der Client befasst sich nie direkt mit der Sammlungsklasse. Er steuert immer den Iterator und sendet ihm die Befehle „Vorwärts“, „Rückwärts“ und „Aktuelles Element abrufen“, um indirekt die gesamte Sammlung zu durchlaufen.
Das Obige ist nur eine kurze Erklärung des Iterator-Musters. Werfen wir einen Blick auf die Iterator-Schnittstelle in Java, um zu sehen, wie sie implementiert ist.
1. java.util.Iterator
In Java ist Iterator nur eine Schnittstelle, die im JDK so definiert ist : Iterator zum Durchlaufen der Sammlung. Iteratoren ersetzen die Enumeration im Java Collections Framework. Es gibt zwei Unterschiede zwischen Iteratoren und Aufzählungen:
1. Iteratoren ermöglichen es dem Aufrufer, mithilfe einer wohldefinierten Semantik Elemente aus der Sammlung zu entfernen, auf die der Iterator während der Iteration zeigt.
2. Der Methodenname wurde verbessert.
Seine Schnittstelle ist wie folgt definiert:
public interface Iterator { boolean hasNext(); Object next(); void remove(); }
Unter ihnen:
Object next(): Gibt das zurück Iterator gerade durchquert Ein Verweis auf ein Element, der Rückgabewert ist Object, das in den von Ihnen benötigten Typ umgewandelt werden muss
boolean hasNext(): Bestimmen Sie, ob im Container zugängliche Elemente vorhanden sind
void remove(): Löschen Sie das Element, das gerade vom Iterator gekreuzt wurde
Für uns müssen wir im Allgemeinen nur next() und hasNext() verwenden, um die Iteration abzuschließen . Wie folgt:
for(Iterator it = c.iterator(); it.hasNext(); ) { Object o = it.next(); //do something }
Wie bereits erläutert, hat Iterator einen großen Vorteil, das heißt, wir müssen die internen Ergebnisse der Sammlung nicht kennen Die Sammlung wird von Iterator durch Vereinheitlichung verwaltet. Die Methoden hasNext() und next() werden verwendet, um das nächste Element zu bestimmen und zu erhalten. Was die spezifische interne Implementierung betrifft, müssen wir uns nicht darum kümmern. Als qualifizierter Programmierer ist es für uns jedoch sehr wichtig, die Implementierung von Iterator herauszufinden. Lassen Sie uns den Quellcode von ArrayList analysieren.
2. Die Implementierung von Iterator für jede Sammlung
Das Folgende ist eine Analyse der Iterator-Implementierung von ArrayList. Tatsächlich verstehen wir die Datenstruktur von ArrayList , Hashset und TreeSet, die interne Implementierung, haben auch eine gute Vorstellung davon, wie sie Iterator implementieren. Da die interne Implementierung von ArrayList Arrays verwendet, müssen wir nur den Index der entsprechenden Position aufzeichnen, und die Implementierung seiner Methode ist relativ einfach.
2.1. Iterator-Implementierung von ArrayList
In ArrayList definieren wir zunächst eine interne Klasse Itr, die die Iterator-Schnittstelle wie folgt implementiert:
private class Itr implements Iterator<E> { //do something }
Die iterator()-Methode von ArrayList implementiert:
public Iterator<E> iterator() { return new Itr(); }
Was also durch die Verwendung der ArrayList.iterator()-Methode zurückgegeben wird, ist die Itr( ) innere Klasse, also müssen wir uns jetzt um die Implementierung der internen Klasse Itr() kümmern:
Drei Variablen vom Typ int sind in Itr definiert: Cursor, lastRet, erwartetModCount. Wobei Cursor die Indexposition des nächsten Elements darstellt und lastRet die Indexposition des vorherigen Elements darstellt
int cursor; int lastRet = -1; int expectedModCount = modCount;
Aus den Definitionen von Cursor und LastRet geht hervor, dass es sich um LastRet handelt Immer eins kleiner als der Cursor, also hasNext () Die Implementierungsmethode ist äußerst einfach. Sie müssen lediglich feststellen, ob Cursor und lastRet gleich sind.
public boolean hasNext() { return cursor != size; }
Die Implementierung von next() ist eigentlich relativ einfach. Geben Sie einfach das Element an der Cursor-Indexposition zurück und ändern Sie dann den Cursor und lastRet
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; //cursor + 1 return (E) elementData[lastRet = i]; //lastRet + 1 且返回cursor处元素 }
checkForComodification() 主要用来判断集合的修改次数是否合法,即用来判断遍历过程中集合是否被修改过。modCount 用于记录 ArrayList 集合的修改次数,初始化为 0,,每当集合被修改一次(结构上面的修改,内部update不算),如 add、remove 等方法,modCount + 1,所以如果 modCount 不变,则表示集合内容没有被修改。该机制主要是用于实现 ArrayList 集合的快速失败机制,在 Java 的集合中,较大一部分集合是存在快速失败机制的,这里就不多说,后面会讲到。所以要保证在遍历过程中不出错误,我们就应该保证在遍历过程中不会对集合产生结构上的修改(当然 remove 方法除外),出现了异常错误,我们就应该认真检查程序是否出错而不是 catch 后不做处理。
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
对于 remove() 方法的是实现,它是调用 ArrayList 本身的 remove() 方法删除 lastRet 位置元素,然后修改 modCount 即可。
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(); } }
以上所述是小编给大家介绍的Java集合Iterator迭代的实现方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对PHP中文网的支持!
更多Java集合Iterator迭代的实现方法相关文章请关注PHP中文网!