2009-07-23 10 views
2

Ich habe einige Probleme mit der Erstellung einer Liste von Objekten basierend auf einer Bedingung auf einem enum. Es scheint, dass, nachdem ich die Liste abgeschlossen habe, jedes Element in der Liste dem letzten Element entspricht.Warum ändern diese Java-Enums Werte?

Es ist der klassische Fall von verschiedenen Referenzen auf das gleiche Objekt zeigen, aber ich weiß nicht, wie es zu vermeiden:

ich Dinge verglichen habe, so viel wie ich kann, während die Lesbarkeit beibehalten:

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

ist die Ausgabe:

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

Wenn jemand erklären kann, warum die erste Instanz von Foo auf der Liste ändert, und wie ich machen kann Liste, die sich nicht ändert, wäre ich dankbar.

EDIT: Ok, ich sehe, wo das Problem jetzt ist. Im realen, viel größeren Programm habe ich ein viel größeres Array, und ich möchte die alten Informationen behalten, wenn ich ein neues Foo für die Liste erstelle. Ich habe den Code geändert, um anzuzeigen, dass weitere Informationen vorhanden sind, die ich beibehalten möchte. Wie erreiche ich das?

+1

In Bezug auf Ihre Bearbeitung, müssen Sie genauer über Ihren Fall, als die offensichtliche Antwort bekommen ist, das Array zu klonen (wie Jon und meine Antwort vermuten). Wenn das Array sehr groß ist, wie ist dann die Beziehung zwischen den alten und den neuen Daten? Möglicherweise benötigen Sie für diesen Zweck eine andere Datenstruktur, aber da wir keinen Einblick in die gespeicherten Daten haben und wie alt und neu Foos sind, kann ich keine guten Vorschläge machen. – Yishai

Antwort

6

Dieses Bit ist der Täter:

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

Sie das Kopieren einer Referenz auf das alte Array Foo, und dann in diesem Array den Wert ändern.

Warum haben Sie sogar ein Array der Größe 1 statt nur Digit? Wenn Sie das Array wirklich wollen, möchten Sie es vielleicht klonen, anstatt nur die Referenz zu kopieren, aber wir können nicht wirklich sagen, was die Absicht ist.

Hier ist ein kürzeres Beispiel:

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

kürzer aber gleicher Fehler, immer noch mit dem gleichen Array –

+0

Vielen Dank, Klon scheint hier für mich arbeiten. –

+0

@Carlos: Das war der springende Punkt - um ein kürzeres Beispiel zu zeigen, das das gleiche Problem zeigt. –

2

In Ihrem zweiten Konstruktor:

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

Sie sind wieder mit der Liste von old. Sie möchten eine Kopie dieser Liste erstellen, anstatt dieselbe Liste zu verwenden. Dazu ändern Sie die Zuordnung zu:

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

Der Objektverweis ist in diesem Fall das Array. Der Konstruktor von foo ist, wo Sie das Problem haben sollten, speziell:

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 
} 

Sie benötigen das Array in ein neues Array im Konstruktor von foo zu kopieren.

2

Das Problem scheint in dieser Linie zu sein:

this.array = old.array; 

Sie Array Referenzen gemeinsam nutzen, so dass jedes Foo die gleiche Array teilt, so dass sie alle den gleichen Wert an array [0].

Um dies zu beheben, versuchen Sie:

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

Dies ist die richtige Lösung, jetzt klonen Sie den Inhalt des Arrays und können eines der Elemente – Salandur

0

Statt

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

}

einfach tun

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

}

Wenn Sie das Array wirklich brauchen ... (am besten wäre eine einfache Ziffer wie in einer anderen Antwort vorgeschlagen)

+0

überschreiben Dies funktioniert für mein Beispiel, aber ich brauchte einige Informationen aus dem alten Array. Ich habe das Beispiel geändert, um dies zu verdeutlichen. –