ホームページ >Java >&#&チュートリアル >Java の Iterable と Iterator の詳細な紹介

Java の Iterable と Iterator の詳細な紹介

不言
不言転載
2018-10-08 15:37:533039ブラウズ

この記事では、Java の Iterable と Iterator について詳しく説明します。必要な方は参考にしていただければ幸いです。

Java では、次の方法で List コレクションを走査できます。

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 + ",");
}

1 つ目は通常の for ループ、2 つ目はイテレータの走査、3 つ目は for each ループです。後の 2 つのメソッドには、Java の反復子オブジェクトと反復可能オブジェクトが含まれます。次に、これら 2 つのオブジェクトの違いと、カスタム クラスでの for each ループの実装方法を見てみましょう。

Iterator と Iterable

iterator は Java のイテレータ オブジェクトであり、List などのコレクションを反復処理できる基礎的な依存関係です。 iterable インターフェイスはイテレータを返すメソッドを定義します。これはイテレータをカプセル化することと同じです。同時に、iterable インターフェイスを実装するクラスは各ループをサポートできます。

Iterator の内部詳細

jdk の Iterator インターフェイスの主なメソッドは次のとおりです。

public interface Iterator<E> {
    boolean hasNext();
    E next();
}

Iterator は、上記の 2 つのメソッドを通じてコレクションへの反復アクセスのメソッドを定義します。 、および特定の実装メソッド さまざまな実装クラスに応じて、特定のコレクション クラスは反復を実装するための Iterator インターフェイスのメソッドを実装します。

List には Iterator インターフェイスが実装されていませんが、Iterable インターフェイスが実装されていることがわかります。 Iterable インターフェイスのソース コードをさらに観察すると、Iterable インターフェイスが Iterator オブジェクトのみを返すことがわかります。

public interface Iterable<T> {
  Iterator<T> iterator();
}

したがって、次のメソッドを使用して List を反復できます (iterator() メソッドを呼び出すことによって)

Iterator it = list.iterator();
while (it.hasNext()) {
    System.out.print(it.next() + ",");
}

同時に、Iterable インターフェイスを実装する場合は、次のメソッドも使用できます。 for each ループ。

for each原則

実際、for each ループは Iterator イテレータにも依存しますが、Java によって提供される構文糖である Java コンパイラは、トラバーサルのためにそれを Iterator イテレータに変換します。各ループについて次のコードを逆コンパイルします。

 for (Integer i : list) {
       System.out.println(i);
   }

逆コンパイル後:

Integer i;
for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(i)){
        i = (Integer)iterator.next();        
    }

Java の for each 拡張ループがイテレータを通じて実装されていることがわかります。

Iterable と Iterator の関係についての詳細な説明

質問があります。なぜ hasNext() メソッドと next() メソッドを Iterable インターフェイスや他のクラスに直接配置しないのですか。それらを直接実装できますか?

その理由は、一部のコレクション クラスには複数のトラバーサル メソッドがあるため、Iterable を実装するクラスは、ListItrLinkedList などの複数の Iterator 内部クラスを実装できるためです。 DescendingIterator2 つの内部クラスは、それぞれ双方向トラバーサルと逆順トラバーサルを実装します。異なる Iterator を返すことで異なるトラバーサル メソッドを実装すると、より柔軟になります。 2 つのインターフェイスをマージすると、異なる Iterator 実装クラスを返すことができなくなります。 ListItr 関連のソース コードは次のとおりです。

    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;
        }
        ...

上記のように、list.listIterator() メソッド (list.iterator()##) を呼び出すことでイテレータを返すことができます。 # は単なるデフォルト実装です )

DescendingIteratorソース コードは次のとおりです:

    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();
        }
    }

このイテレータは

list.descendingIterator()# を通じて使用することもできます。 ##。 独自のイテレータを実装する

これでカスタム クラス ArrayMap ができました。これをそれぞれ次のように走査すると、次のようになります。

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

for (String s: am) {
   System.out.println(s);
}

hashNext と next を実装していないため、抽象メソッドであるため、トラバースすることはできません。

カスタマイズされたイテレータ クラス

最初にイテレータ クラスをカスタマイズして hashNext メソッドと next メソッドを実装し、それを ArrayMap の内部クラスとして使用します。関連するコードは次のとおりです。 # #次で指定した走査ルールが ArrayMap のキー値に基づいて走査されることがわかります。上記のイテレータ クラスを使用すると、イテレータ メソッドを使用して外部からトラバースできます。トラバース コードは次のとおりです。

   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;
        }
    }

上に示すように、反復アクセス用の KeyIterator オブジェクトを作成します (外部クラスによって、内部クラスオブジェクト)。

各ループのサポート

反復可能なインターフェイスが実装されていないため、現在は各ループのアクセスをサポートできません。まず ArrayMap に Iterable インターフェイスを実装します。

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());
}

その後、再起動します。 iterator() メソッドを記述し、独自のイテレータ オブジェクト (iterator) を返します。

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;
    }
  ....
}

カスタム KeyIterator クラスは Iterator インターフェイスを実装する必要があることに注意してください。実装しないと、 iterator() メソッドで返される型は一致しません。

以上がJava の Iterable と Iterator の詳細な紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcnblogs.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。