Heim  >  Artikel  >  Java  >  Detaillierte Einführung in Iterable und Iterator in Java

Detaillierte Einführung in Iterable und Iterator in Java

不言
不言nach vorne
2018-10-08 15:37:532950Durchsuche

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 und Iterable

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.

Interne Details zum Iterator

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.

Prinzip von for every

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.

Ausführliche Diskussion der Beziehung zwischen Iterable und Iterator

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)

DescendingIteratorDer 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.

Implementieren Sie Ihren eigenen Iterator

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.

Angepasste Iteratorklasse

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).

Unterstützung für jede Schleife

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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:cnblogs.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen