ArrayList - Objekt kopieren und ändern

Diskutiere ArrayList - Objekt kopieren und ändern im Java Basics - Anfänger-Themen Bereich.
M

mace

Hallo zusammen,
Es ist eigentlich ganz simpel: Ich möchte ein bestehendes Objekt in einer ArrayList duplizieren (der ArrayList am Ende anfügen) und die Kopie ändern.
Aus irgendeinem Grund wird jedoch bei der Änderung des neuen Objekts auch das Ursprungsobjekt geändert. Woran liegt das bzw. wie kann ich das vermeiden?

Danke im Voraus & Grüße!

Java:
sequence = sequence + 1;

opShapeData.add(opShapeData.get(selectedActivityIndex));
shape shape = new shape();
shape = opShapeData.get(sequence - 1); // - 1 da sequence bei 1 startet und selectedActivityIndex bei 0
shape.setSequence(sequence);
shape.setId("New Id");
opShapeData.set(sequence - 1, shape);
Die ArrayList verwende ich als ObservableList in einem Javafx-Tableview. Die Kopie soll logischerweise vom aktuell selektierten Element (selectedActivityIndex) erzeugt werden.

Ergebnis:
Code:
----- No.: 0 | sequence: 2 | Id: New Id
----- No.: 1 | sequence: 2 | Id: New Id
 
T

temi

Vermutlich erzeugst du keine Kopie, sondern kopierst nur die Referenz auf das ursprüngliche Objekt, damit hast du dann zwei Variablen, die auf das selbe Objekt zeigen.

BTW: Klassennamen sollten groß geschrieben werden, Variablennamen klein: shape shape = new shape(); kann gar nicht funktionieren.
 
M

mace

Ja, das mit der Referenz habe ich mir schon gedacht. Leider finde ich nichts zum Kopieren von einzelnen Elementen einer ArrayList, nur zum Kopieren von ganzen ArrayLists. Über einen Hinweis, wie ich es richtig mache, wäre ich sehr dankbar.

Auch danke für den Hinweis mit den Klassennamen. Hat bisher glücklicherweise funktioniert.
 
T

temi

Leider finde ich nichts zum Kopieren von einzelnen Elementen einer ArrayList
Es geht weniger um die ArrayList, sondern um den Typ der darin gespeichert ist. Den musst du kopieren.

Viele Klassen bieten einen Kopierkonstruktor an
Java:
Rectangle rect1 = new Rectangle();
Rectangle rect2 = new Rectangle(rect1); // Kopie von rect1
Generell, würde ich zuerst das Objekt aus der Liste holen, verändern und danach in der Liste speichern.
Java:
Shape shape = new Shape(opShapeData.get(selectedActivityIndex)); // Ich weiß nicht was Shape ist und ob es einen Kopierkonstuktor gibt
shape.setSequence(sequence);
shape.setId("New Id");
opShapeData.add(shape);
Vielleicht wird auch clone() unterstützt?
Java:
Shape shape = opShapeData.get(selectedActivityIndex).clone();
 
M

mace

Erst einmal danke für den Hinweis. Die Klasse Shape habe ich selbst erstellt. Aus den Shapes werden in einer anderen Funktion SVG-Grafiken erstellt. Ich werde mal schauen, ob ich selbst eine Methode zum Kopieren hinbekomme. Klingt elegant und ich werde es noch öfter benötigen.
 
T

temi

Erst einmal danke für den Hinweis. Die Klasse Shape habe ich selbst erstellt. Aus den Shapes werden in einer anderen Funktion SVG-Grafiken erstellt. Ich werde mal schauen, ob ich selbst eine Methode zum Kopieren hinbekomme. Klingt elegant und ich werde es noch öfter benötigen.
Schreib dir einen Kopierkonstruktor, der ein Shape als Parameter hat und von diesem die Eigenschaften übernimmt.
 
M

mace

Da ich gelesen habe, dads jeder Java-Anfänger irgendwann auf das Thema trifft, anbei meine Lösung.
Das Thema des Kopierens von Objekten ist nicht trivial. Wie Temi schreibt, erstellt man in den meisten Fällen keine Kopie sondern nur eine Referenz auf denselben Speicherbereich, was dazu führt, dass altes und neues Objekt quasi verbunden bleiben. Die Stichworte sind Shallow copy bzw. Deep copy. Benötigt man eigenständige Kopie, ist Deep copy die richtige Wahl. Auch dafür gibt es verschiedene Varianten.

Diese Links haben mir geholfen:
https://www.programmingmitra.com/20...nstructor-versus-Object-clone-or-cloning.html
https://www.codevscolor.com/java-deepcopy-serializationutils-example/

Java:
sequence = sequence + 1;

Shape oldShape = opShapeData.get(selectedActivityIndex);
Shape newShape = SerializationUtils.clone(oldShape);

newShape.setSequence(sequence - 1);

opShapeData.add(newShape);
Die Objektklasse muss dafür Serializable implementieren.

Java:
public class Shape implements Serializable {
...
Danke an Temi für den richtigen Hinweis.
 
mrBrown

mrBrown

Du hast damit die so ziemlich umständlichste Lösung gefunden, das ist durch die Brust dann durch den Zeh und dann ins Auge :)

Ein einfacher Copy-Konstruktor ist da die einfachste und beste Variante. (Und trivial ist der auch ;) )
 
M

mace

Hmm, ein Java-Nicht-Anfänger teilt in einem Java-Anfänger-Bereich einem Java-Anfänger mit, was trivial ist und was nicht. Nun, Überraschung: Trivial oder nicht hängt doch arg von der Perspektive ab. Mein 6-Jähriger Sohn kann mir sicher auch Integralrechnung erklären, weil er schon 1+1 rechnen kann. Diesen supereinfachen Copy-Konstruktor habe ich jedenfalls nicht auf Anhieb hinbekommen und der Autor des Artikel im ersten Link wird sicherlich auch keine Ahnung haben (vor allem kann ich das als Anfänger gut beurteilen). Aber danke für den lehrreichen Kommentar.
 
mrBrown

mrBrown

Hmm, ein Java-Nicht-Anfänger teilt in einem Java-Anfänger-Bereich einem Java-Anfänger mit, was trivial ist und was nicht. Nun, Überraschung: Trivial oder nicht hängt doch arg von der Perspektive ab. Mein 6-Jähriger Sohn kann mir sicher auch Integralrechnung erklären, weil er schon 1+1 rechnen kann. Diesen supereinfachen Copy-Konstruktor habe ich jedenfalls nicht auf Anhieb hinbekommen und der Autor des Artikel im ersten Link wird sicherlich auch keine Ahnung haben (vor allem kann ich das als Anfänger gut beurteilen). Aber danke für den lehrreichen Kommentar.
Ein Copy-Konstruktor nutzt nur die absoluten Java-Grundlagen: Konstruktoren und Zuweisungen. Um bei deinem Beispiel zu bleiben: Das ist auf dem Nivea von 1+1.

Deine Variante (bzw die beiden Varianten aus deinen Links) nutzen clone und Serialisierung. Beide Konzepte sind große Fehler von Java und führen ständig zu Problemen, sowohl aufgrund ihrer konkreten Umsetzung (mit Marker-Interfaces statt richtigen Interfaces), als auch aufgrund des Konzepts.
Clone wäre dabei sogar noch passend, wenn man ein Objekt "klonen" will - Serialisierung zu nutzen ist aber wirklich ein Umweg um drei Ecken, und eher auf dem Niveau der Integralrechnung.

In beiden Fällen ist aber ein Copy-Konstruktor deutlich einfacher.

Um das mal gegenüber zu stellen:

Das ist der Copy-Konstrukutor aus deinem ersten Link in sinnvoll:
Java:
public Person(Person original) {
    this.id = original.id + 1;
    this.name = original.name;
    this.city = original.city;
}
Alles, was da drin vor kommt ist eine Konstruktor-Deklaration und drei Zuweisungen - beides nicht wirklich kompliziert und für jeden Einsteiger der schon Konstruktoren kennt verständlich.



Das dagegen ist der Weg über Serialisierung:

Java:
class Person implements Serializable {...}

public Person copy(Person original) throws IOException, ClassNotFoundException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream out = new ObjectOutputStream(bos);
    out.writeObject(original);

    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
    ObjectInputStream in = new ObjectInputStream(bis);
    return (Person) in.readObject();
}
Statt einem Konstruktor mit drei Zuweisungen muss man:
* Interfaces kennen
* Exceptions kennen
* grundsätzlich Input/Output-Streams verstanden haben
** Wrappen von Streams verstanden haben
** ByteArray*Stream kennen
** Object*Stream kennen
* Casten verstanden haben
* und nutzt zusätzlich eine API mit X Fallstricken und Beschränkungen.
 
T

temi

Diesen supereinfachen Copy-Konstruktor habe ich jedenfalls nicht auf Anhieb hinbekommen
Ich hatte doch dazu geschrieben wie es geht
Kopierkonstruktor, der ein Shape als Parameter hat und von diesem die Eigenschaften übernimmt
Du hättest auch gerne noch mal nachfragen dürfen, wenn noch etwas unklar war. Wobei sogar bei deinem ersten Link wird ziemlich weit unten erwähnt, dass der Kopierkonstruktor der beste Weg ist, inkl. Beispiel.
Copy Constructors
This method copying object is most popular between developer community it overcomes every design issue of Object.clone() and provides better control over object construction
 
Thema: 

ArrayList - Objekt kopieren und ändern

Passende Stellenanzeigen aus deiner Region:
Anzeige

Neue Themen

Anzeige

Anzeige
Oben