JavaのFor-Eachとポインター[複製]
質問
この質問にはすでに回答があります:
わかりました。したがって、ArrayListを反復処理して特定の要素を削除するようにしています。ただし、For-Eachのような構造を使用すると問題が発生します。次のコードを実行すると:
ArrayList<String> arr = new ArrayList<String>();
//... fill with some values (doesn't really matter)
for(String t : arr)
{
t = " some other value "; //hoping this would change the actual array
}
for(String t : arr)
{
System.out.println(t); //however, I still get the same array here
}
私の質問、「t」を「arr」へのポインタにすると、for-eachループの値を変更できるようになりますか?別の構造を使用してArrayListをループできることはわかっていますが、これはとてもきれいで読みやすいように見えます。「t」をポインタにできると便利です。
すべてのコメントを歓迎します!たとえそれを吸い込んで別の構造を使用するべきだと言っても。
解決
最良のアプローチはforループを使用することだと思います。
ArrayList<String> arr = new ArrayList<String>();
for (int i = 0; i < arr.size(); i++) {
String t = arr.get(i);
if (// your condition is met) {
arr.set(i, "your new value");
}
}
他のヒント
問題は、ループスコープのリファレンス t
を変更して、新しいStringインスタンスを指すようにすることです。これは機能しません。 arraylistの実際のエントリは参照しません。参照の実際の値を変更する必要があります。 String
が可変で、そのための架空の set()
メソッドを提供した場合、理論上は可能です
for (String t : arr) {
t.set("some other value");
}
またはそうですが、それは不変なので不可能です。通常の for
ループを使用して、配列自体のエントリポイントのハンドルを取得する方が良い:
for (int i = 0; i < arr.size(); i++) {
arr.set(i, "some other value");
}
拡張された for
ループの使用を主張する場合、 String
を StringBuilder
に置き換える必要があります。これは可変です:
for (StringBuilder t : arr) {
t.delete(0, t.length()).append("some other value");
}
Javaは参照渡しではなく値渡しであることに注意してください。
For-eachはインデックスポインターを提供しないため、不変の値を変更するために使用することはできません。
いずれもインデックス付きのforループを使用するか、可変型(StringではなくStringBufferなど)を使用します
Javaのオブジェクト(文字列など)の配列は、順序付けられた一連の参照を含む連続したブロックです。したがって、4つの文字列の配列がある場合、実際に持っているのは、配列に格納されている4つの参照と、配列の外側にあるがその4つの要素によって参照される4つの文字列オブジェクトです。
Javaのfor-eachコンストラクトは、ローカル変数を作成し、反復ごとに、その反復に対応する配列セルからの参照をそのローカル変数にコピーします。ループ変数を設定すると( t =&quot; some other value&quot;
)、新しい文字列&quot; some other value&quot;
への参照をローカルに配置します配列にではなく、変数t。
ループ変数が配列/リスト要素自体のエイリアスのように機能する他の言語(Perlなど)とは対照的です。
コードは、コンパイラによって次のように書き直されます。
ArrayList<String> arr = new ArrayList<String>();
//... fill with some values (doesn't really matter)
for (final Iterator <String> i = arr.iterator(); i.hasNext();) {
String t;
t = i.next();
t = " some other value "; // just changes where t is pointing
}
希望することを行うには、次のようにforループを記述する必要があります。
for (final ListIterator<String> i = arr.iterator(); i.hasNext();) {
final String t;
t = i.next();
i.set("some other value");
}
Iteratorにはsetメソッドがありません。ListIteratorのみにあります。
基本的に、リストarrから文字列tを削除します。 arr.remove(t)を実行するだけで完了です。 しかし同じリストを繰り返し処理している間はできません。この方法でリストを変更しようとすると、例外が発生します。
2つのオプションがあります:
- リストのクローンを作成し、クローンを反復処理し、元のリストから「特定の」文字列を削除します
- 削除候補のリストを作成し、そのリストにすべての「特定の」文字列を追加し、元のリストを反復処理した後、ごみ箱を反復処理して、ここで収集したすべてを元のリストから削除します。
オプション1は簡単です。クローンは次のように作成できます。
List<String> clone = new ArrayList<String>(arr);
Javaでオブジェクト/参照がどのように機能するかを誤解しているようです。これは、言語を効果的に使用するための基本です。ただし、ここのこのコードは必要なことを行う必要があります(説明がないことをおapび申し上げます):
ArrayList<String> arr = new ArrayList<String>();
//... fill with some values (doesn't really matter)
for(int i = 0; i < arr.size(); i++)
{
arr.set(i, " some other value "); // change the contents of the array
}
for(String t : arr)
{
System.out.println(t);
}
これは不変または可変に関係しないと思います。
t = " some other value "; //hoping this would change the actual array
tは、実際のオブジェクトへの参照を保持しません。 Javaはarraylistから値をコピーし、その値をtに入れて、配列リストの値が影響しないようにします。
HTH
これはよく回答されています。まだここに私の提案があります。ループ内のvar tはそこにのみ表示されます。ループの外側では見えません。 String
でない場合は、 t.set()
を実行できます。
プレーンな文字列ではなく、 StringBuffer
を使用します。これにより、中の文字列は変更可能です。
文字列は不変です。 StringBuilder / Bufferのような可変型がある場合は、繰り返しで文字列を変更できます。参照があります。覚えておいてください。