Dieser Artikel bietet Ihnen eine detaillierte Einführung in Iterable und Iterator in Java. Ich hoffe, dass er für Freunde hilfreich ist.
In Java können wir die List-Sammlung auf folgende Weise durchlaufen:
List<Integer> list = new ArrayList<>(); list.add(5); list.add(23); list.add(42); for (int i = 0; i < list.size(); i++) { System.out.print(list.get(i) + ","); } Iterator it = list.iterator(); while (it.hasNext()) { System.out.print(it.next() + ","); } for (Integer i : list) { System.out.print(i + ","); }
Die erste ist eine gewöhnliche for-Schleife, die zweite ist eine Iterator-Durchquerung und die dritte ist eine for-each-Schleife. Die beiden letztgenannten Methoden umfassen Iteratoren und iterierbare Objekte in Java. Schauen wir uns als Nächstes den Unterschied zwischen diesen beiden Objekten an und wie man eine for-each-Schleife in einer benutzerdefinierten Klasse implementiert.
Iterator ist ein Iteratorobjekt in Java, das die zugrunde liegende Abhängigkeit darstellt, die über eine Sammlung wie List iterieren kann. Die iterierbare Schnittstelle definiert eine Methode zum Zurückgeben des Iterators, die der Kapselung des Iterators entspricht. Gleichzeitig können Klassen, die die iterierbare Schnittstelle implementieren, jede Schleife unterstützen.
Die Hauptmethoden der Iterator-Schnittstelle in JDK sind wie folgt:
public interface Iterator<E> { boolean hasNext(); E next(); }
Iterator definiert die Methode des iterativen Zugriffs auf die Sammlung über die beiden oben genannten Methoden und die spezifische Implementierungsmethode Abhängig von verschiedenen Implementierungsklassen implementiert die spezifische Sammlungsklasse die Methoden in der Iterator-Schnittstelle, um die Iteration zu implementieren.
Es kann festgestellt werden, dass die Iterator-Schnittstelle nicht in List implementiert ist, die Iterable-Schnittstelle jedoch implementiert ist. Eine weitere Betrachtung des Quellcodes der Iterable-Schnittstelle zeigt, dass sie lediglich ein Iterator-Objekt zurückgibt.
public interface Iterable<T> { Iterator<T> iterator(); }
Wir können also die folgende Methode verwenden, um die Liste zu iterieren (durch Aufrufen der iterator()-Methode).
Iterator it = list.iterator(); while (it.hasNext()) { System.out.print(it.next() + ","); }
Wenn Sie gleichzeitig die Iterable-Schnittstelle implementieren, können Sie diese auch verwenden die für jede Schleife.
Tatsächlich basiert die for every-Schleife auch auf dem Iterator-Iterator, aber der von Java bereitgestellte syntaktische Zucker wird vom Java-Compiler zum Durchlaufen in einen Iterator-Iterator umgewandelt . Wir dekompilieren Folgendes für jede Schleife:
for (Integer i : list) { System.out.println(i); }
Nach der Dekompilierung:
Integer i; for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(i)){ i = (Integer)iterator.next(); }
Sie können sehen, dass Java für jede erweiterte Schleife durch einen Iterator implementiert wird.
Ich habe eine Frage: Warum nicht einfach die Methoden hasNext() und next() direkt in die Iterable-Schnittstelle und andere Klassen einfügen? kann man sie direkt umsetzen?
Der Grund dafür ist, dass einige Sammlungsklassen möglicherweise mehr als eine Traversal-Methode haben. Eine Klasse, die Iterable implementiert, kann mehrere interne Klassen von Iterator implementieren, z. B. die beiden internen Klassen LinkedList
und ListItr
in DescendingIterator
Es werden jeweils eine bidirektionale Durchquerung und eine Durchquerung in umgekehrter Reihenfolge implementiert. Implementieren Sie verschiedene Durchlaufmethoden, indem Sie unterschiedliche Iterator
zurückgeben, was flexibler ist. Wenn Sie die beiden Schnittstellen zusammenführen, können Sie keine unterschiedlichen Iterator
-Implementierungsklassen zurückgeben. Der relevante Quellcode von ListItr lautet wie folgt:
public ListIterator<E> listIterator(int index) { checkPositionIndex(index); return new ListItr(index); } private class ListItr implements ListIterator<E> { ... ListItr(int index) { // assert isPositionIndex(index); next = (index == size) ? null : node(index); nextIndex = index; } public boolean hasNext() { return nextIndex < size; } ...
Wie oben gezeigt, kann der Iterator durch Aufrufen der Methode list.listIterator()
zurückgegeben werden (list.iterator()
ist nur seine Standardimplementierung)
DescendingIterator
Der Quellcode lautet wie folgt:
public Iterator<E> descendingIterator() { return new DescendingIterator(); } private class DescendingIterator implements Iterator<E> { private final ListItr itr = new ListItr(size()); public boolean hasNext() { return itr.hasPrevious(); } public E next() { return itr.previous(); } public void remove() { itr.remove(); } }
Der Iterator kann auch über list.descendingIterator()
verwendet werden.
Wir haben jetzt eine benutzerdefinierte Klasse ArrayMap, wenn wir sie nun für jede wie folgt durchlaufen:
ArrayMap<String, Integer> am = new ArrayMap<>(); am.put("hello", 5); am.put("syrups", 10); for (String s: am) { System.out.println(s); }
Da wir hashNext und next abstract nicht implementiert haben Methode, daher kann sie nicht durchlaufen werden.
Wir passen zunächst eine Iteratorklasse an, um die Methoden hashNext und next zu implementieren, und verwenden sie als interne Klasse von ArrayMap. Der relevante Code lautet wie folgt:
public class KeyIterator implements Iterator<K> { private int ptr; public KeyIterator() { ptr = 0; } @Override public boolean hasNext() { return (ptr != size); } @Override public K next() { K returnItem = keys[ptr]; ptr += 1; return returnItem; } }
Sie können sehen, dass die Traversierungsregel, die wir als Nächstes angegeben haben, basierend auf dem Schlüsselwert von ArrayMap durchlaufen wird. Mit der oben genannten Iterator-Klasse können wir die Iterator-Methode verwenden, um sie extern zu durchlaufen. Der Durchlaufcode lautet wie folgt:
ArrayMap<String, Integer> am = new ArrayMap<>(); am.put("hello", 5); am.put("syrups", 10); ArrayMap.KeyIterator ami = am.new KeyIterator(); while (ami.hasNext()) { System.out.println(ami.next()); }
Erstellen Sie wie oben gezeigt ein KeyIterator-Objekt für den iterativen Zugriff (beachten Sie, dass die externe Klasse ein internes Klassenobjekt).
Wir können den Zugriff auf jede Schleife derzeit nicht unterstützen, da wir die iterierbare Schnittstelle nicht implementiert haben. Implementieren Sie zuerst die iterierbare Schnittstelle in ArrayMap:
public class ArrayMap<K, V> implements Iterable<K> { private K[] keys; private V[] values; int size; public ArrayMap() { keys = (K[]) new Object[100]; values = (V[]) new Object[100]; size = 0; } .... }
Dann starten Sie neu Schreiben Sie die Methode iterator() und geben Sie unser eigenes Iteratorobjekt (iterator) zurück
@Override public Iterator<K> iterator() { return new KeyIterator(); }
Beachten Sie, dass unsere benutzerdefinierte KeyIterator-Klasse die Iterator-Schnittstelle implementieren muss, da sonst der in der Methode iterator() zurückgegebene Typ nicht übereinstimmt.
Das obige ist der detaillierte Inhalt vonDetaillierte Einführung in Iterable und Iterator in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!