2009-07-23 9 views
2

enumの条件に基づいてオブジェクトのリストを作成するのに問題があります。私はリストを完成した後、リストのすべてのアイテムは最後のアイテムと同等であるようです。これらのJava enumが値を変更するのはなぜですか?

それは同じオブジェクトを指して異なる参照の古典的なケースだが、私はそれを回避する方法がわからない:

可読性維持しながら、私は私ができる限りの事を下に切り詰めました:

をここで
public class Foo { 
    Digit[] array = new Digit[2]; 
    ArrayList<Foo> foozlets; 

    Foo() { 
    array[0] = Digit.ZERO; 
    foozlets = new ArrayList<Foo>(); 
    } 

    Foo(Foo old, Digit num) { 
    this.array = old.array; \\This line is a problem, what should it say? 
    array[1] = num; 
    } 

    public static void main(String[] args) { 
    Foo f = new Foo(); 
    System.out.println("Initial Foo:"); 
    System.out.println(f); 
    f.listFoozlets(); 
    } 

    void listFoozlets() { 
    for (Digit k : Digit.values()) { 
     if (k == Digit.TWO || k == Digit.FIVE) { 
     foozlets.add(new Foo(this, k)); 
     System.out.println("** Foozlet being added **"); 
     Foo foo = new Foo(this, k); 
     System.out.println(foo); 
     } 
    } 
    System.out.println("** List of Foozlets **"); 
    for (Foo foo : foozlets) { 
     System.out.println(foo); 
    } 
    } 

    public String toString() { 
    return array[0].toString() + " " + array[1].toString(); 
    } 
} 

enum Digit { ZERO, ONE, TWO, THREE, FOUR, FIVE } 

が出力されます。

Initial Foo: 
ZERO NULL 
** Foozlet being added ** 
ZERO TWO 
** Foozlet being added ** 
ZERO FIVE 
** List of Foozlets ** 
ZERO FIVE 
ZERO FIVE 

誰かがリストの変更にFooの理由最初のインスタンスを説明することができ、そしてどのように私が作ることができる場合変更されないリスト、私は感謝します。

編集: [OK]をクリックして、問題の原因を確認します。実際のはるかに大きなプログラムでは、私ははるかに大きな配列を持っています。リストのために新しいFooを作成するときに古い情報を保持したいのです。私は、維持したい追加の情報があることを反映するようにコードを変更しました。これをどのように達成するのですか?

+1

あなたの編集については、明白な答え配列をクローンすることです(Jonと私の答えが示唆するように)。配列が非常に大きい場合、古いデータと新しいデータとの関係は何ですか?これを達成するためには、別のデータ構造が必要かもしれませんが、保存されているデータと古いFoosと新しいFoosの関係についての洞察がないので、私は良い提案はできません。 – Yishai

答えて

6

このビットが犯人である:

Foo(Foo old, Digit num) { 
    this.array = old.array; 
    array[0] = num; 
} 

あなたが古いのFooの配列へ参照をコピーし、その配列内の値を変更しています。

なぜ、Digitの代わりにサイズ1の配列がありますか?実際に配列が必要な場合は、単に参照をコピーするのではなく複製することができますが、意図が何であるかは実際には分かりません。 2番目のコンストラクタで

enum Digit { ZERO, ONE, TWO, THREE, FOUR, FIVE } 

public class Foo { 
    Digit[] array = new Digit[1]; 

    Foo() { 
    array[0] = Digit.ZERO; 
    } 

    Foo(Foo old, Digit num) { 
    this.array = old.array; 
    array[0] = num; 
    } 

    public String toString() { 
    return array[0].toString(); 
    } 

    public static void main(String[] args) { 
    Foo f = new Foo(); 
    System.out.println(f); 
    Foo other = new Foo(f, Digit.ONE); 
    System.out.println(f); 
    } 
} 
+0

同じ配列を使用していますが、同じエラーですが短くなりました –

+0

ありがとう、クローンがここで私にとってうまくいくようです。 –

+0

@Carlos:それは全体的な点です - 同じ問題を示すより短い例を示すこと。 –

2

Foo(Foo old, Digit num) { 
    this.array = old.array; 
    array[0] = num; 
} 

あなたがリストを、使用して再しているoldから

はここで短い例です。同じリストを使用するのではなく、そのリストのコピーを作成したいとします。割り当てを次のように変更することでこれを行うことができます。

Foo(Foo old, Digit num) { 
    this.array = new ArrayList<Foo>(old.array); 
    array[0] = num; 
} 
1

この場合のオブジェクト参照は配列です。あなたは具体的には、問題を抱えている場所のfooのコンストラクタは次のとおりです。

Foo(Foo old, Digit num) { 
    this.array = old.array; // reference the old array 
    array[0] = num; // set the first element of the array (for this AND the old array) to num 
} 

あなたがfooのコンストラクタで新しい配列に配列をコピーする必要があります。

2

問題は、この行にあるように表示されます。

this.array = old.array; 

あなたは配列参照を共有しているので、すべてのFooのは、同じ配列を共有するので、それらすべてが[0]の配列で同じ値を持っています。

この問題を解決するには、試してみてください。

this.array = old.array.clone(); 
+0

これは正しい解決策です。今度は配列の内容を複製して、要素の1つを上書きすることができます – Salandur

0

代わりの

Foo(Foo old, Digit num) { 
    this.array = old.array; 
    array[0] = num; 

}

を簡単に行う

Foo(Foo old, Digit num) { 
    array[0] = num; 

}

本当に配列が必要な場合は... (別の返信で提案されているように、最善の方法は単純な数字を使用することです)

+0

これは私の例では機能しますが、古い配列からの情報が必要でした。私はこれを反映するために例を変更しました。 –

関連する問題