69

以下のコードで私を助けてください、値を変更した後でも同じ出力が得られます

import java.util.*;

class Test {
    public static void main(String[] args) {
        ArrayList<Integer> a = new ArrayList<Integer>();

       // added 0-9 to ArrayList        
          for(int i=0;i<9;i++)
            a.add(new Integer(i));

        // initialize the Iterator
        Iterator<Integer> i = a.iterator();

        // changed the value of first element in List
        if(i.hasNext()) {
            Integer x = i.next();
            x = Integer.valueOf(9);
        }

        // initialized the iterator again and print all the elements
        i = a.iterator();
        while(i.hasNext())
            System.out.print(i.next());
    }
}    

//Output : 012345678

値 9 は更新されていません。

4

7 に答える 7

91

リストは、リストに格納されている元の値へのオブジェクト参照を維持しています。したがって、この行を実行すると:

Integer x = i.next();

とリストの両方xが同じオブジェクトへの参照を格納しています。ただし、実行すると:

x = Integer.valueOf(9);

リストは何も変更されていませんがx、別のオブジェクトへの参照が格納されています。リストは変更されていません。次のようないくつかのリスト操作メソッドを使用する必要があります。

list.set(index, Integer.valueof(9))

注:他の人が示唆しているように、これはの不変性とは何の関係もありません。Integerこれは、基本的な Java オブジェクト参照の動作です。


ポイントを説明するのに役立つ完全な例を次に示します。ListIteratorこれは、イテレーションの途中でアイテムの削除/設定をサポートするクラスを使用することに注意してください。

import java.util.*;

public class ListExample {

  public static void main(String[] args) {

    List<Foo> fooList = new ArrayList<Foo>();
    for (int i = 0; i < 9; i++)
      fooList.add(new Foo(i, i));

    // Standard iterator sufficient for altering elements
    Iterator<Foo> iterator = fooList.iterator();

    if (iterator.hasNext()) {
      Foo foo = iterator.next();
      foo.x = 99;
      foo.y = 42;
    }

    printList(fooList);    

    // List iterator needed for replacing elements
    ListIterator<Foo> listIterator = fooList.listIterator();

    if (listIterator.hasNext()) {
      // Need to call next, before set.
      listIterator.next();
      // Replace item returned from next()
      listIterator.set(new Foo(99,99));
    }

    printList(fooList);
  }

  private static void printList(List<?> list) {
    Iterator<?> iterator = list.iterator();
    while (iterator.hasNext()) {
      System.out.print(iterator.next());
    }
    System.out.println();
  }

  private static class Foo {
    int x;
    int y;

    Foo(int x, int y) {
      this.x = x;
      this.y = y;
    }

    @Override
    public String toString() {
      return String.format("[%d, %d]", x, y);
    }
  }
}

これは印刷されます:

[99, 42][1, 1][2, 2][3, 3][4, 4][5, 5][6, 6][7, 7][8, 8]
[99, 99][1, 1][2, 2][3, 3][4, 4][5, 5][6, 6][7, 7][8, 8]
于 2012-10-07T20:14:03.717 に答える
12

最初の要素の値を変更していると言うところ。

x = Integer.valueOf(9);

xまったく新しい整数を指すように変更していますが、二度と使用しません。コレクションを変更することはありません。

ArrayList を使用しているため、要素を変更できるイテレータが必要な場合は ListIterator を使用できます。これは、変更が必要なコードのスニペットです。

//イテレータを初期化
ListIterator <Integer> i = a. listIterator() ;

//リストの最初の要素の値を変更
if(i.hasNext()) {
    i.next();
    i.set(Integer.valueOf(9));     // イテレータが現在ある要素を変更します
}

// 新しい反復子で、すべての要素を出力します
。反復子 iter = a.iterator();
while(iter.hasNext())
    System.out.print(iter.next());

>> 912345678

残念ながら、同じことを Set<T> のような他のコレクションに拡張することはできません。実装の詳細 (たとえば、HashSet がハッシュ テーブルとして実装され、オブジェクトを変更するとハッシュ値が変更される可能性があるため、反復順序が変更される可能性があります) Set<T> を「新規追加/削除のみ」タイプのデータ構造にし、コンテンツを変更します。それを繰り返している間はまったく安全ではありません。

于 2012-10-07T20:11:51.270 に答える
1

私はダンカンに同意します...可変オブジェクトで試しましたが、それでも同じ問題が発生します...これに対する簡単な解決策を得ました...イテレータの代わりにListIteratorを使用し、ListIteratorのsetメソッドを使用します

ListIterator<Integer> i = a.listIterator();
//changed the value of first element in List
Integer x =null;
        if(i.hasNext()) {
            x = i.next();
            x = Integer.valueOf(9);
        }
    //set method sets the recent iterated element in ArrayList
    i.set(x);
        //initialized the iterator again and print all the elements
        i = a.listIterator();
        while(i.hasNext())
        System.out.print(i.next());

しかし、これは ListIterator を使用できる ArrayList に対してのみこれを使用するように制限します...他のコレクションでも同じ問題が発生します

于 2012-10-07T20:57:44.310 に答える
1

問題は、あなたがその声明を考えていることだと思います...

x = Integer.valueOf(9);

... '9' の値が、x が参照しているオブジェクトに (!) '格納' されます。

しかし、それは間違っています。

代わりに、ステートメントは、あなたが呼び出すかのように何かを引き起こします

x = new Integer(9); 

Java ソース コードを見れば、何が起こっているかが詳細にわかります。

「Integer」クラスの「valueOf(int i)」メソッドのコードは次のとおりです。

public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

さらに、IntegerCache クラスが初めて使用されるたびに、次のスクリプトが呼び出されます。

static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }

valueOf メソッドで「new Integer(i)」を使用して新しい整数オブジェクトが作成されるか、または IntegerCache に格納されている整数オブジェクトへの参照が返されることがわかります。

どちらの場合も、x は新しいオブジェクトを参照します。

これが、呼び出したときにリスト内のオブジェクトへの参照が失われる理由です...

x = Integer.valueOf(9);

そうする代わりに、 ListIterator と組み合わせて ...

i.set(Integer.valueOf(9));

...変更したい要素を取得したら...

i.next();
于 2014-09-12T17:29:35.070 に答える
1

リストの値を変更しようとしていますが、x の参照を変更しているだけです。以下を実行すると、x のみが変更され、コレクション内の何も変更されません。

x = Integer.valueOf(9);

さらに、Integer不変です。つまり、Integer オブジェクト内の値を変更することはできません (これを行うには別のメソッドが必要になります)。これは、オブジェクト全体を置き換える必要があることを意味します。これを で行う方法はありませんIterator(独自のボクシング レイヤーを追加する必要はありません)。代わりに次の操作を行います。

a.set(0, 9);
于 2012-10-07T20:12:30.723 に答える
0

に変更しますfor(int i=0;i<=9;i++)

于 2014-12-03T04:40:24.173 に答える