JComponent klonen?

Status
Nicht offen für weitere Antworten.

0001001

Bekanntes Mitglied
Ich hab hier eine Klasse die JComponent erweitert:
Code:
public class MyClass extends JComponent{
   private String value1;
   ...
}

In meinem Quellcode erstelle ich ein Object der Klasse:
Code:
MyClass myclass = new MyClass();

Jetzt hätte ich gerne einen Klon des Objekts myclass.
Per:
Code:
MyClass myclass2 = myclass;
bekomme ich ja nur eine Referenz richtig?

Wie kann ich myclass richtig klonen, so dass ich zwei eigenständige Objekte haben, die die identischen Werte gesetzt haben?
 

Marco13

Top Contributor
Weder das eine noch das andere ist praktikabel (oder auch nur "möglich" auf Basis dessen, was bisher an Anforderungen genannt wurde).

Ein Copy-Konstruktor scheitert an den privaten Fields von JComponent, und ein "clone" liefert irgendwas beliebiges, aber mit Sicherheit erstmal Mist.

Die einzig vernünftige Lösung ist, ein neues Objekt zu erstellen (bzw. eine Methode zu schreiben, die einem ein neues Objekt liefert - falls neben dem Konstruktoraufruf noch irgendwelche "initialisierungen" gemacht werden müssen)
 

André Uhres

Top Contributor
0001001 hat gesagt.:
Jetzt hätte ich gerne einen Klon des Objekts myclass.
Per:
Code:
MyClass myclass2 = myclass;
bekomme ich ja nur eine Referenz richtig?
Richtig.
Zum Klonen können wir die Schnittstelle "Cloneable" implementieren. Beispiel:
Code:
/*
 * MyClass.java
 */

import java.awt.*;
import javax.swing.*;

public class MyClass extends JComponent implements Cloneable {

    private String value1;
    private JLabel label;

    public MyClass(String value) {
        value1 = value;
        setPreferredSize(new Dimension(100, 100));
        setBorder(BorderFactory.createLineBorder(Color.BLACK));
        label = new JLabel(value1);
        label.setBounds(10, 10, 60, 22);
        add(label);
    }

    @Override
    public String toString() {
        return "value1: " + value1;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        MyClass result = (MyClass) super.clone();
        /*
         * Hier könnte es auch noch nötig sein, "mutable" Objekte zu kopieren und die 
         * Referenzen zu diesen Objekten mit Referenzen auf den Kopien zu ersetzen. 
         * Am einfachsten erreichen wir dies, indem wir rekursiv "clone" auf den 
         * betreffenden Feldern aufrufen. Es kann u.U. aber auch notwendig sein, 
         * eine "tiefe" Kopie zu erstellen.
         */
        return result;
    }
}
Das Klonen selbst geschieht einfach mit dem Aufruf von clone(). Beispiel:
Code:
myClass = new MyClass("001");
try {
    myClass2 = (MyClass) myClass.clone();
} catch (CloneNotSupportedException ex) {
    ex.printStackTrace();
}
Siehe auch: Minitutorial-Cloneable
Je nachdem, was dein JComponent machen soll, ist die Lösung von Marco13 vorzuziehen.
In meinem Beispiel teilen sich myClass und myClass2 z.B. dieselbe Instanz vom JLabel, was u.U. nicht
erwünscht ist. Im Allgemeinen sollte das Objekt, das von clone() zurückkommt, unabhängig vom
geklonten Objekt sein.
 

Marco13

Top Contributor
André Uhres hat gesagt.:
In meinem Beispiel teilen sich myClass und myClass2 z.B. dieselbe Instanz vom JLabel, was u.U. nicht
erwünscht ist.

Das ist sicher nicht erwünscht - man kann diese Component ja nicht anzeigen, oder überhaupt sinnvoll für irgendwas verwenden. Deswegen auch der Hinweis, dass ein "clone" mit ziemlicher Sicherheit Mist liefert. Auch ein "deep clone" läßt sich nicht vernünftig implementieren. Wenn an der Ursprungscomponent ein MouseListener hängt, und dieser MouseListener enthält über 3 Ecken wieder die Ursprungscomponent, geht das muntere Referenzen-Auflösen los. Das an sich wäre noch nicht unlösbar, aber relativ aufwändig. Richtig schwierig wird es dadurch, (dass JComponent ja schon nicht Cloneable implementiert, und) JComponent einige Referenzen auf Singletons enthält (irgendwelche Manager, RepaintManager oder so...). Zusammenfassend würde ich sagen, dass so ein Clonen schlicht und einfach nicht praktikabel ist. (Hm. Hab ich ja schon. Egal)
 
S

shad0w

Gast
Wenn es nicht so sehr auf Geschwindigkeit ankommt, könnte man es auch serialisieren und dann wieder deserialisieren:

Code:
        MyClass mc1 = new MyClass();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(mc1);
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        MyClass mc2 = (MyClass)ois.readObject();
 

André Uhres

Top Contributor
Marco13 hat gesagt.:
André Uhres hat gesagt.:
In meinem Beispiel teilen sich myClass und myClass2 z.B. dieselbe Instanz vom JLabel
Das ist sicher nicht erwünscht - man kann diese Component ja nicht anzeigen
Wir können diese Component zwar anzeigen, was sie u.U. sinnvoll einsetzbar macht,
aber es hängt, wie gesagt, davon ab, was die JComponent machen soll.
Aber wir haben ja noch deine Lösung, die ich auch vorziehe. Ich wollte nur das Prinzip des Klonens zeigen.
Aber ehrlich gesagt, würde ich das bei JComponent auch lieber weglassen.
 

Marco13

Top Contributor
Ich denke nicht, dass das gehen wird: Wenn man auf dem Label dann "getParent" aufruft, wird ja immernoch das "alte" Parent zurückgegeben, und nicht der Klon.... Aber wer will, kanns ja trotzdem gern versuchen :wink:
 
S

shad0w

Gast
Bei meiner Lösung ist das aber nicht so.

Wenn ich diesen Code ausführe...

Code:
class MyClass extends JComponent {
    JLabel label;
    
    public MyClass() {
        label = new JLabel("Hi!");
        add(label);
    }
}

public class Main {
 
    public static void main(String[] args) throws Exception {
        
        MyClass mc1 = new MyClass();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(mc1);
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        MyClass mc2 = (MyClass)ois.readObject();
        
        System.out.println(mc1.label.getParent() == mc2.label.getParent());
    }

}

... kommt false raus. JLabel ist auch serializable, weil JComponent serializable ist.

In JComponent gibt es extra für diese Belange die Methoden writeObject und readObject, damit die Serialisierung korrekt funktioniert.

Also, ich halte die Serialisierung und Deserialisierung für das beste, weil die API das explizit unterstützt.
 

Marco13

Top Contributor
OK, bei Component-Hierarchien wird dieser eine Punkt noch funktionieren. Aber was ist z.B. mit MouseListenern, die an einem Label hängen?
 
S

shad0w

Gast
Doch, das funktioniert auch, wenn du deinen MouseListener serializable machst. Probier's mal aus.
 

Marco13

Top Contributor
Da JComponent serialzable ist wird das in den meisten Fällen funktionieren, aber die Annahme, dass jeder Listener (Mouse, MouseMotion, PropertyChange, ComponentListener etc) der da "vielleicht" dranhängt, serializable ist, ist ungerechtfertigt. WENN alles Serializable ist, funktioniert es, aber man kann einfach nicht davon ausgehen. (Außer, wenn das in einem komplett "privaten", abgeschotteten Zusammenhang verwendet wird - aber selbst DANN wäre mir immernoch unwohl dabei - Serialization ist einfach nicht zum Klonen gedacht ... )
 
S

shad0w

Gast
Ob es erforderlich ist, dass alle Listeners auch noch geklont werden, müsste der Threadersteller uns sagen. Oft ist es nicht erforderlich bzw. sogar unerwünscht.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
O Test auf JComponent Java Basics - Anfänger-Themen 7
JFeel-x JComponent<-----Eigenschaften<-- Als Liste abfragen? Java Basics - Anfänger-Themen 8
N Mit MouseEvent und JComponent Elementnamen bekommen Java Basics - Anfänger-Themen 5
K Swing JComponent Java Basics - Anfänger-Themen 6
G Kreis auf JComponent zeichnen Java Basics - Anfänger-Themen 8
G bild aus jcomponent, speichersparend? Java Basics - Anfänger-Themen 4
J Welt in GameOfLife klonen Java Basics - Anfänger-Themen 9
S Objekte klonen und Deep Copy Java Basics - Anfänger-Themen 30
D komplexe Datenstrukturen "klonen" Java Basics - Anfänger-Themen 4
M Methoden Array unbedingt klonen? und Point Frage. Java Basics - Anfänger-Themen 4
M Variablen return-array klonen Java Basics - Anfänger-Themen 3
P Tiefes Klonen Java Basics - Anfänger-Themen 2
U ArrayList Klonen Java Basics - Anfänger-Themen 15
W Java Fenster durch Buttonclick klonen Java Basics - Anfänger-Themen 4
B OOP Objekt klonen (Grundzustand), um in Editor "Abbrechen" zu können Java Basics - Anfänger-Themen 4
K Klonen und Kopieren von Dateien Java Basics - Anfänger-Themen 6
B JPanel klonen Java Basics - Anfänger-Themen 13
B LinkedList klonen Java Basics - Anfänger-Themen 8
T Fehlermeldung beim Klonen eines JPanels Java Basics - Anfänger-Themen 8
M ResultSet klonen Java Basics - Anfänger-Themen 6
S Objekt klonen mit clone() Java Basics - Anfänger-Themen 3

Ähnliche Java Themen

Neue Themen


Oben