Objekt kopieren.
-
Guten Morgen. Ich habe eine Klasse, die ein int Array (3 x 3) verwaltet. Nun möchte ich diese array in ein neues Objekt kopieren. Dazu habe ich mir ein neues Objekt der gleichen Klasse erstellt, alle Werte des int mit einer get Funktion aus dem alten Objekt ausgelesen und mit einer seet in das neue Objekt eingefügt. Das hat auch geklappt. Nun aber das Problem mache ich eine Änderung ( ein Feld neu beschreiben) habe ich auch die Änderung an der Kopie. Ich habe den Eindruck, dass ich nicht nur die Werte sondern eine Refernz kopiert habe, aber wie macht man das richtig ?
--edit: Objekt im Titel mit ck. :o
-
Poste am Besten mal deinen Code. Dann können wir gucken was genau du machst.
-
Ich gehe mal davon aus das du nicht wirklich eine tiefe Kopie erzeugst. Wie du selbst schon bemerkt hast kopierst du nur referenzen. Der richtige weg wäre:
Du erzeugst beim Kopieren auch wieder ein int Array der selben Größe wie das Quellarray und übernimmst jeden Wert einzeln.
Prinzipell ist in Java alles was nicht Primitiv ist (int,bool) [alles was an Variablentypen mit Kleinbuchstaben beginnt.] und ich glaube die String-Klasse da bin ich mir nicht sicher. Eine Referenz. Das heißt wenn ich solche Werte an etwas anderes zuweise. Habe ich eine Referenz. Wenn ich also an einen Objekt was ändere, ändere ich das andere Objekt mit.
Ein allgemeines tiefes Kopieren (für alle Klassen die Serializable sind) geht auch über einen memory stream. Da musst du mal ein wenig im Google suchen.
-
Fedaykin schrieb:
Prinzipell ist in Java alles was nicht Primitiv ist (int,bool) [alles was an Variablentypen mit Kleinbuchstaben beginnt.] und ich glaube die String-Klasse da bin ich mir nicht sicher.
Jup, die String-Klasse ist unveränderlich. Sobald ein String verändert wird, wird eine neue Instanz angelegt und der Originalstring wird nicht verändert.
-
Okay hier ist mein Quellcode :
import java.awt.Point; public class PlayingField implements Cloneable{ // Konstruktor public PlayingField(){ FieldValues = new int[3][3]; } public PlayingField clone() throws CloneNotSupportedException{ PlayingField ReturnValue = (PlayingField)super.clone(); return ReturnValue; } // Funktion zum Schreiben von Werten // field => Ponit mit Koordinaten // value => Wert der geschrieben werden soll public boolean setValue(Point field, int value){ if (FieldValues[field.x][field.y] != 0){ return false; } FieldValues[field.x][field.y] = value; return true; } public boolean setValue(int x, int y, int value){ return setValue(new Point(x, y), value); } // Funktion zum Schreiben von Werten // field => Ponit mit Koordinaten public int getValue(Point field){ return FieldValues[field.x][field.y]; } public int getValue(int x, int y){ return getValue(new Point(x,y)); } private int FieldValues[][]; } /*import java.awt.Point; public class PlayingField{ // Default - Konstruktor public PlayingField(){ } // Default - Konstruktor public PlayingField(int field[][]){ for (int x = 0; x < GlobalConstants.FieldRows; x++){ for (int y = 0; y < GlobalConstants.FieldColumns; y++){ Field[x][y] = field[x][y]; } } } public void PrintField(){ for (int x = 0; x < GlobalConstants.FieldRows; x++){ for (int y = 0; y < GlobalConstants.FieldColumns; y++){ System.out.print( getValue(new Point(x,y))); } System.out.println(); } } public PlayingField clone(){ int temp[][] = {};//new int[GlobalConstants.FieldRows][GlobalConstants.FieldColumns]; System.arraycopy(Field, 0, temp, 0, 9 ); PlayingField theClone = new PlayingField(temp); return theClone; } // Get Wert vom Feld public int getValue(Point field){ if ((field.x >= GlobalConstants.FieldRows) || (field.y >= GlobalConstants.FieldColumns)){ return GlobalConstants.GameColorInvalid; } return Field[field.x][field.y]; } public int getValue(int x, int y){ return getValue(new Point(x, y)); } // Setzt einen Wert public boolean setValue(Point field, int value){ switch (getValue(field)) { case GlobalConstants.GameColor1: case GlobalConstants.GameColor2: case GlobalConstants.GameColorInvalid: return false; case GlobalConstants.GameColorUndefiend: Field[field.x][field.y] = value; } return true; } // Gibt den Gewinner zurück public int getWinner(){ int ReturnValue = GlobalConstants.GameWinnerUndefined; if (getGameStatus() != GlobalConstants.GameStatusRunning) { // Prüfe die Zeilen for (int y = 0; y < GlobalConstants.FieldColumns; y++){ for (int x = 0; x < GlobalConstants.FieldRows - 1; x++){ if (getValue(x, y) == getValue(x + 1, y)){ ReturnValue = getValue(x, y); } else{ ReturnValue = GlobalConstants.GameWinnerUndefined; } } } // Prüfe die Spalten for (int x = 0; x < GlobalConstants.FieldColumns; x++){ for (int y = 0; y < GlobalConstants.FieldRows - 1; y++){ if (getValue(x, y) == getValue(x + 1, y)){ ReturnValue = getValue(x, y); } else{ ReturnValue = GlobalConstants.GameWinnerUndefined; } } } // Prüfe die Diagonalen for (int x = 0; x < GlobalConstants.FieldColumns - 1; x++){ if (getValue(x, x) == getValue(x + 1, x + 1)){ ReturnValue = getValue(x, x); } else{ ReturnValue = GlobalConstants.GameWinnerUndefined; } } // Prüfe die Diagonalen int y = 0; for (int x = GlobalConstants.FieldColumns - 1; x >= 1; x--){ if (getValue(x, y) == getValue(x - 1, y + 1)){ ReturnValue = getValue(x, y); } else{ ReturnValue = GlobalConstants.GameWinnerUndefined; } y++; } } else { return GlobalConstants.GameWinnerUndefined; } return ReturnValue; } // Gibt den Spiel Status zurück private int getGameStatus(){ int ReturnValue = GlobalConstants.GameStatusFinished; for (int x = 0; x < GlobalConstants.FieldRows; x++){ for (int y = 0; y < GlobalConstants.FieldColumns; y++){ if ( getValue(x,y) == GlobalConstants.GameColorUndefiend ) return GlobalConstants.GameStatusRunning; } } return ReturnValue; } //private int Field[][] = new int[GlobalConstants.FieldRows][GlobalConstants.FieldColumns]; private int Field[][] = new int[GlobalConstants.FieldRows][GlobalConstants.FieldColumns]; } */
UNd hier wird der Code aufgerufen.
PlayingField field = new PlayingField(); PlayingField field2 = null; try { // make deep copy of the object of type CloneExp field2= (PlayingField)field.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } field.setValue(1, 1, 2); System.out.println("Orginal"); PrintField(field); System.out.println("Kopie "); PrintField(field2);
DAs Resultat ist, dass nach dem set in beiden Onketen an der Stelle 1,1 der wert 2 drin steht. ICh will aber das er nur in Field steht und nicht in beiden
-
Hat denn keiner eine idee?
public PlayingField clone() throws CloneNotSupportedException{ PlayingField ReturnValue = (PlayingField)super.clone(); ReturnValue.FieldValues = new int[3][3]; //Kopiere alle Einträge for (int x = 0; x < 3; x++){ for (int y = 0; y < 3; y++){ ReturnValue.FieldValues[x][y] = getValue(x,y); } } //ReturnValue.FieldValues. = FieldValues.clone(); return ReturnValue; }
Ich habe das so gemacht. Geht das einfacher ?
-
Soweit ich weis nein. Da super.clone() nur das Objekt und nicht dein Array cloned musst du das so per Hand machen.
-
Nimm halt das "Im Speicher kopieren" Quelltext stammt von hier:
http://www.informatik-student.de/2006/12/10/deep-copy-von-java-objekten/import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class DeepObjectCopy { public static Object clone(Object copyObject) { try { //erzeugen einen streams im ram ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); //erzeugen eines object streams um den bytearray ObjectOutputStream oos = new ObjectOutputStream(baos); //schreiben des objektes oos.writeObject(copyObject); //erzeugen eines Inputstream aus dem Bytearray ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); //erzeugen eines ObjectInputstreams um den ByteArray ObjectInputStream ois = new ObjectInputStream(bais); //Lesen des Objektes (ggf richtig casten) Object deepCopy = ois.readObject(); return deepCopy; } catch (IOException e) { e.printStackTrace(); } catch(ClassNotFoundException e) { e.printStackTrace(); } return null; } }
das ganze geht prinzipiell für alles was Serializable ist.
-
Fragt sich nur, ob eine Kopie wirklich nötig ist. Man findet eigentlich nie einen guten Grund um ein Objekt zu kopieren.
-
DEvent schrieb:
Fragt sich nur, ob eine Kopie wirklich nötig ist. Man findet eigentlich nie einen guten Grund um ein Objekt zu kopieren.
-Copy and Paste support
-Multiple Ansichten auf Datenstrukturen (da braucht man teilweise tiefe Kopien zumindest das meiste was der Darstellung dient sollte da Kopiert werden).
-Objektfabriken per PrototypingIch denke mal ein paar Szenarien findet man noch. Wenns kein Anwendungsfall für sowas gäbe, gäbe es keine Möglichkeiten sowas zu machen.
-
Fedaykin schrieb:
DEvent schrieb:
Fragt sich nur, ob eine Kopie wirklich nötig ist. Man findet eigentlich nie einen guten Grund um ein Objekt zu kopieren.
-Copy and Paste support
-Multiple Ansichten auf Datenstrukturen (da braucht man teilweise tiefe Kopien zumindest das meiste was der Darstellung dient sollte da Kopiert werden).
-Objektfabriken per PrototypingIch denke mal ein paar Szenarien findet man noch. Wenns kein Anwendungsfall für sowas gäbe, gäbe es keine Möglichkeiten sowas zu machen.
Für Copy and Paste, da erstellt man ein neues Objekt und kopiert die Daten. Da ist ein Copy-Ctor besser als die Clone Methode. Bei multiple Ansichten wird einfach ein Wrapper-Objekt erstellt, der dann die Daten des richtigen Objektes zurückliefert. Da ist kein Kopieren nötig und eher hinterlich. Bei Objektfabriken erstellt man das Objekt und setzt dann die Werte, wie normal auch.
Wann ist den wirklich die Methode clone() nötig? Doch nur, wenn man wirklich rohe Objekte abspeichern muss (also java.lang.Object) und man Kopien braucht.
-
DEvent schrieb:
Für Copy and Paste, da erstellt man ein neues Objekt und kopiert die Daten. Da ist ein Copy-Ctor besser als die Clone Methode.
Zeig mir das Interface welches die Implementation eines solchen Constructors Garantiert
DEvent schrieb:
Bei multiple Ansichten wird einfach ein Wrapper-Objekt erstellt, der dann die Daten des richtigen Objektes zurückliefert. Da ist kein Kopieren nötig und eher hinterlich.
Und was ist wenn ich gewisse Teile der Sichten modifizeren möchte? Ich stelle mir unter den Sichten das ganze so vor das ich eine Basissicht kopiere und die neu erstellte "View" dann bearbeiten kann, aber die Basissicht unverändert bleibt. Nur bei teilen wo ich es mir wünsche habe ich die Referenz auf ein richtiges Objekt die in beiden Sichten geändert wird.
DEvent schrieb:
Bei Objektfabriken erstellt man das Objekt und setzt dann die Werte, wie normal auch.
Ich habe hier extra das Prototyping angeführt. Es gibt Anwendungsfälle bei denen ich mein Objekt als Prototyp bei einer Objektfabrik anmelden möchte. Fordere ich eine Instanz dieses Prototypes an wird dieser gecloned und zurück geliefert. Da spart die Clone methode entsprechende Fallunterscheidungen in der Fabrik.
DEvent schrieb:
Wann ist den wirklich die Methode clone() nötig? Doch nur, wenn man wirklich rohe Objekte abspeichern muss (also java.lang.Object) und man Kopien braucht.
Das ist wohl nun jeden seine Sache. Die Frage stellt sich eher, ob man das Basisclone verwenden sollte, oder sich eigene Clone Methoden mit spezielleren Rückgabetypen schreibt.