Maison > Java > javaDidacticiel > Introduction détaillée à Iterable et Iterator en Java

Introduction détaillée à Iterable et Iterator en Java

不言
Libérer: 2018-10-08 15:37:52
avant
3086 Les gens l'ont consulté

Cet article vous apporte une introduction détaillée à Iterable et Iterator en Java. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

En Java, nous pouvons parcourir la collection List des manières suivantes :

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 + ",");
}
Copier après la connexion

La première est une boucle for ordinaire, la seconde est une traversée d'itérateur et les Trois sont les pour chaque boucle. Les deux dernières méthodes impliquent des objets itérateurs et itérables en Java. Examinons ensuite les différences entre ces deux objets et comment implémenter une boucle for each dans une classe personnalisée.

Iterator et Iterable

iterator est un objet itérateur en Java, qui est la dépendance sous-jacente qui peut parcourir une collection telle que List. L'interface itérable définit une méthode qui renvoie l'itérateur, ce qui équivaut à encapsuler l'itérateur. En même temps, les classes qui implémentent l'interface itérable peuvent prendre en charge chaque boucle.

Détails internes de l'Iterator

Les principales méthodes de l'interface Iterator dans jdk sont les suivantes :

public interface Iterator<E> {
    boolean hasNext();
    E next();
}
Copier après la connexion

Iterator définit la méthode d'accès itératif à la collection via ce qui précède deux méthodes, et l'implémentation spécifique dépend de différentes classes d'implémentation. La classe de collection spécifique implémente les méthodes dans l'interface Iterator pour implémenter l'itération.

On peut constater que l'interface Iterator n'est pas implémentée dans List, mais que l'interface Iterable est implémentée. Une observation plus approfondie du code source de l'interface Iterable montre qu'elle renvoie simplement un objet Iterator.

public interface Iterable<T> {
  Iterator<T> iterator();
}
Copier après la connexion

On peut donc utiliser la méthode suivante pour itérer la List (en appelant la méthode iterator())

Iterator it = list.iterator();
while (it.hasNext()) {
    System.out.print(it.next() + ",");
}
Copier après la connexion

En même temps, si vous implémentez l'interface Iterable, vous pouvez également utiliser la boucle for each.

Principe de for each

En fait, la boucle for each s'appuie également sur l'itérateur Iterator, mais le sucre syntaxique fourni par Java, le compilateur Java le convertira en itérateur Iterator pour le parcours . Nous décompilons ce qui suit pour chaque boucle :

 for (Integer i : list) {
       System.out.println(i);
   }
Copier après la connexion

Après la décompilation :

Integer i;
for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(i)){
        i = (Integer)iterator.next();        
    }
Copier après la connexion

Vous pouvez voir que Java pour chaque boucle améliorée est implémenté via l'itérateur.

Discussion approfondie de la relation entre Iterable et Iterator

J'ai une question, pourquoi ne pas simplement mettre les méthodes hasNext() et next() directement dans l'interface Iterable et d'autres classes peut-on les mettre en œuvre directement ?

La raison est que certaines classes de collection peuvent avoir plus d'une méthode de parcours. Une classe qui implémente Iterable peut implémenter plusieurs classes internes Iterator, telles que les deux classes internes LinkedList et ListItr dans DescendingIterator. Le parcours bidirectionnel et le parcours inverse sont implémentés respectivement. Implémentez différentes méthodes de parcours en renvoyant différents Iterator, ce qui est plus flexible. Si vous fusionnez les deux interfaces, vous ne pouvez pas renvoyer des classes d'implémentation Iterator différentes. Le code source pertinent de ListItr est le suivant :

    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;
        }
        ...
Copier après la connexion

Comme indiqué ci-dessus, l'itérateur peut être renvoyé en appelant la méthode list.listIterator() (list.iterator() n'est que son implémentation par défaut)

DescendingIteratorLe code source est le suivant :

    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();
        }
    }
Copier après la connexion

Cet itérateur peut également être utilisé via list.descendingIterator().

Implémentez votre propre itérateur

Nous avons maintenant une classe personnalisée ArrayMap, maintenant si nous la parcourons pour chacun comme suit :

ArrayMap<String, Integer> am = new ArrayMap<>();
am.put("hello", 5);
am.put("syrups", 10);

for (String s: am) {
   System.out.println(s);
}
Copier après la connexion

Puisque nous ne l'avons pas implémenté hashNext et ensuite les méthodes abstraites, elles ne peuvent donc pas être parcourues.

Classe d'itérateur personnalisée

Nous personnalisons d'abord une classe d'itérateur pour implémenter les méthodes hashNext et next, et l'utilisons comme classe interne d'ArrayMap. Le code pertinent est le suivant :

<🎜. >
   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;
        }
    }
Copier après la connexion
Vous pouvez voir que la règle de traversée que nous avons spécifiée dans la suite consiste à parcourir en fonction de la valeur clé d'ArrayMap. Avec la classe itérateur ci-dessus, nous pouvons utiliser la méthode itérateur pour le parcourir en externe. Le code de traversée est le suivant :

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());
}
Copier après la connexion
Comme indiqué ci-dessus, l'accès itératif est effectué en créant un objet KeyIterator (notez l'objet externe). objets de classe internes de création de classe).

Prise en charge de chaque boucle

Nous ne pouvons pas prendre en charge l'accès à chaque boucle pour le moment car nous n'avons pas implémenté l'interface itérable. Implémentez d'abord l'interface Iterable dans 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;
    }
  ....
}
Copier après la connexion
Remplacez ensuite la méthode iterator() et renvoyez notre propre objet itérateur (iterator)

    @Override
    public Iterator<K> iterator() {
        return new KeyIterator();
    }
Copier après la connexion
Notez que notre classe KeyIterator personnalisée doit implémenter l'interface Iterator, sinon dans la méthode iterator() les types renvoyés ne correspondent pas .

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers numéros
Impossible d'installer Java
Depuis 1970-01-01 08:00:00
0
0
0
Java peut-il être utilisé comme backend du Web ?
Depuis 1970-01-01 08:00:00
0
0
0
Installer JAVA
Depuis 1970-01-01 08:00:00
0
0
0
Aide : Données chiffrées JAVA Décryptage PHP
Depuis 1970-01-01 08:00:00
0
0
0
Est-ce en langage Java ?
Depuis 1970-01-01 08:00:00
0
0
0
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal