大家讲道理2017-04-17 14:59:37
特定の言語の実装は異なります。言語に依存しない点がいくつかあります
走査中に配列にデータを追加すると、不完全な走査 (新しいメンバーの長さが変化するため) または無限ループ (常に新しいメンバーが入ってくるため) が発生します
トラバーサル中にデータが削除された場合、配列アクセスは範囲外になります (長さが短くなり、ポインターが空としてマークされた領域を指すため)
@Terry_139061 の答えとして、トラバーサル中にノード自体のデータを変更するだけであれば、一般的には安全です (もちろん、特定のシナリオによって異なります)
PHP中文网2017-04-17 14:59:37
問題の説明はあまり正確ではありません。タグは java
と lisp
です。私は少しラケットのコードを書いただけなので、次のデフォルトの変更は の追加/削除操作です。リスト
まず第一に、Java にはさまざまな種類のリストがあります:
リーリー このうち、CopyOnWriteArrayList
は、読み取りと書き込みを分離することでエラーが発生しません。 Wiki の Copy-on-write を参照してください。
リーリー
は、アクセスするオブジェクトを削除するか、配列が範囲外になるか、追加を続けて無限シーケンスを生成する場合を除き、for ループ内で変更しても問題ありません。for
の場合、 iterator.remove() を使用しても問題はありません。 iterator.remove() は iterator
を設定するためです。
リーリー
リーリー
は本質的に暗黙的な反復子です (javap -c を使用してバイトコードを比較できます)。expectedModCount はリセットされないため、list.remove() を使用するときは、iterator.next( ) 教えてくれます foreach
ConcurrentModificationException
リーリー
天蓬老师2017-04-17 14:59:37
これは変更できます。次のプログラムは 3 aaaaa
トラバースにどのような方法を使用しましたか?分析に役立つようにコードを投稿してください。
高洛峰2017-04-17 14:59:37
Java の観点からこの質問に答えると、Iterator パターンはコレクション クラスを横断するための標準的なアクセス方法です。さまざまなタイプのコレクション クラスからアクセス ロジックを抽象化できるため、コレクションの内部構造がクライアントに公開されるのを回避できます。
たとえば、Iterator が使用されていない場合、配列を反復処理するにはインデックスを使用します。
クライアントは、コレクションの内部構造を事前に知っておく必要があります。アクセス コードとコレクション自体は密接に結合されており、アクセス ロジックをコレクション クラスとクライアント コードから分離することはできません。トラバーサル メソッドの場合、クライアント コードは再利用できません。
さらに恐ろしいのは、将来 ArrayList を LinkedList に置き換える必要がある場合、元のクライアント コードを完全に書き直す必要があることです。上記の問題を解決するために、Iterator モードは常に同じロジックを使用してコレクションを走査します。
リーリー- その秘密は、クライアント自体がコレクションを走査するための「ポインター」を維持しないことです。すべての内部状態 (現在の要素の位置、次の要素があるかどうかなど) はイテレーターによって維持され、このイテレーターはファクトリ メソッドを通じてコレクション クラスによって生成されるため、コレクション全体を走査する方法がわかります。クライアントはコレクション クラスを直接処理することはなく、常に Iterator を制御し、「forward」、「backward」、および「get the current element」コマンドを送信して、コレクション全体を間接的に走査します。
Iterator を使用してコレクション要素を反復処理する場合、collection はコレクション要素自体を反復変数に渡しませんが、コレクション要素の値を反復変数に渡します。したがって、反復変数の値を変更しても、コレクション要素自体の値は変更されません。イテレータ イテレータはオブジェクトを保存せず、Collection オブジェクトに添付され、コレクションを走査するためにのみ使用されます。イテレータ イテレータは、フェールファスト メカニズムを使用します。反復プロセス中にコレクションが変更されたことが検出されると、プログラムは変更された結果を表示する代わりに、ただちに java.util.ConcurrentModificationException をスローします。これにより、リソースの共有によって引き起こされる潜在的な問題が回避されます。
{ str = "hello" } ステートメントを実行しても、 iterator.remove() を実行すると、現在の反復オブジェクトが削除され、java が報告されます。 .util.ConcurrentModificationException は、コレクションの要素が変更されたことを検出するためです。