# Object mit clone kopieren



## Generic1 (5. Jul 2010)

Hallo,

mir ist folgender Code nicht gnaz klar, ich kopiere eine Hashtable mit clone() und es wird eine Shallow- Copy gemacht -> das heißt für mich, dass nur die Referenz auf die Hashtable kopiert wird nicht aber deren Inhalt -> aber es wird anscheinend doch das ganze Objekt gekloned, also ein deep copy gemacht?
Kann da jemand was dazu sagen.



```
package dictionarytest;

import java.util.Hashtable;

public class Main {

    public Main() {
        final Hashtable dictionary = new Hashtable();
        dictionary.put("key1", "value1");
        dictionary.put("key2", "value2");
        dictionary.put("key3", "value3");
        dictionary.put("key4", "value4");
        dictionary.put("key5", "value5");
        dictionary.put("key6", "value6");
        System.out.println("Dictionary: " + dictionary);
        
        final Hashtable newHashtable = (Hashtable)dictionary.clone();
        newHashtable.put("key1", "valueNeu");
        System.out.println("dictionary: " + dictionary + ", newHashtable:" + newHashtable);
        }

    public static void main(String[] args) {
        final Main main = new Main();
        }
}
```


----------



## Gast2 (5. Jul 2010)

Die Referenzen der Einträge werden ebenfalls kopiert.
Wenn du allerdings einen eintrag in dictionary änderst, ändert sich der selbe Eintrag in newHashTable. Daher ist das keine deep copy.


----------



## SlaterB (5. Jul 2010)

ob clone() für die Keys und Werte "key1" und Co. echte Kopien erstellt oder die Originalobjekte wiederverwendet, wäre für das Beispiel irrelevant,
dass mindestens die Map neu erstellt wird, kann man doch erwarten, 
also wird nach neuer Value-Zuordnung garantiert die Ausgabe kommen wie sie kommt

alles andere wäre ja
> final Hashtable newHashtable = dictionary;
statt
> final Hashtable newHashtable = (Hashtable)dictionary.clone();
dafür brauchts keine clone()-Methode..


----------



## Generic1 (5. Jul 2010)

Eben nicht, probiers mal aus, es kommt folgendes raus:


```
Dictionary: {key6=value6, key5=value5, key4=value4, key3=value3, key2=value2, key1=value1}
dictionary: {key6=value6, key5=value5, key4=value4, key3=value3, key2=value2, key1=value1}, newHashtable:{key6=value6, key5=value5, key4=value4, key3=value3, key2=value2, key1=valueNeu}
```

Nö, verstehs jetzt ehrlich gesagt nicht. Wenn ich clone() mache, dann hab ich meiner Meinung nach 2 Referenzen auf die Hashtable und ob ich mit der einen oder der anderen referenz einen value über einen key ändere müsste ja egal sein, oder?


----------



## gman (5. Jul 2010)

Hi,

die Java-API-Doc sagt zu "Objekt.clone()":



> By convention, the object returned by this method should be independent of this object (which is being cloned).


----------



## Michael... (5. Jul 2010)

Schau Dir doch die Implementierung von clone() in der Hashtable an:
Es wird eine neue Hashtable erzeugt in die geklonte Entries (ebenfalls neu erzeugt) eingefügt werden.
Einzig das Schlüssel-Werte-Paar bleibt erhalten.
Es wird alse eine Art middle-deep-copy gemacht ;-)


----------



## Michael... (5. Jul 2010)

Zur Veranschaulichung:

```
final Hashtable<String, JLabel> origTable = new Hashtable<String, JLabel>();
origTable.put("k1", new JLabel("original"));
origTable.put("k2", new JLabel());
System.out.println("Dictionary key1: " + origTable.get("k1").getText());

final Hashtable<String, JLabel> cloneTable = (Hashtable<String, JLabel>) origTable.clone();
cloneTable.get("k1").setText("ueberschrieben");
System.out.println("Original key1: " + origTable.get("k1").getText());
System.out.println("Clone key1   : " + cloneTable.get("k1").getText());
```


----------



## SlaterB (5. Jul 2010)

immer gerne angemerkt: nie (Hashtable<String, JLabel>) schreiben, generisch sicher ist das sowieso nicht, (Hashtable) reicht


----------



## Michael... (5. Jul 2010)

SlaterB hat gesagt.:


> immer gerne angemerkt: nie (Hashtable<String, JLabel>) schreiben, generisch sicher ist das sowieso nicht, (Hashtable) reicht


Sorry  war nur als Bsp gedacht.
Aber gerade da sollte man vielleicht auf saubern Code achten - nicht, dass den einer auch noch kopiert ;-)


----------



## Generic1 (6. Jul 2010)

OK, ich nehme es zur Kenntnis, dass es so funktioniert mit JLabel, mit Strings ist das wahrscheinlich ein bisschen anders gelagert, da Strings immutable sind: 


```
final Hashtable<String, String> origTable = new Hashtable<String, String>();
        origTable.put("k1", new String("original1"));
        origTable.put("k2", new String("original2"));
        System.out.println("Dictionary key1: " + origTable.get("k1"));
        
        final Hashtable<String, String> cloneTable = (Hashtable<String, String>) origTable.clone();
        cloneTable.put("k1", "ueberschrieben");
        System.out.println("Original key1: " + origTable.get("k1"));
        System.out.println("Clone key1   : " + cloneTable.get("k1"));
```

Man kann also sagen, dass mit einer Hashtable, die nur Strings enthält, eine komplette Deep Copy erzeugt wird!?


----------



## Michael... (6. Jul 2010)

Generic1 hat gesagt.:


> Man kann also sagen, dass mit einer Hashtable, die nur Strings enthält, eine komplette Deep Copy erzeugt wird!?


Von deep copy würde ich da nicht sprechen. Mit Strings ist das so ne Sache, quasi halb Objekt halb primitiv, auf jeden Fall immutable - wie Du schon angemerkt hast. D.h. Du kannst das "Stringobjekt" in Deiner Hashtable nicht mehr ändern, aber Du kannst - wie in Deinem Codebeispiel - einen neuen String in die geklonte Hashtable stecken. Da die geklonte Hashtable inkl. deren Entries neu erzeugte Objekte sind und der eingefügte String ein neues "Objekt" ist, wirkt sich das nicht auf die originale Hashtable aus.


----------



## SlaterB (6. Jul 2010)

noch ne allgemeine Weisheit: nie new String() schreiben!

und zum JLabel-Beispiel:
wenn du da ein neues JLaben einfügen würdest
cloneTable.put("k2", new JLabel("other"));
dann wäre der Inhalt wieder unterschiedlich

aber es besteht schon ein Unterschied zu String, eben dass man das JLabel (beibehalten und) ändern kann, einen String ist unveränderbar


----------



## VfL_Freak (6. Jul 2010)

Moin,



SlaterB hat gesagt.:


> noch ne allgemeine Weisheit: nie new String() schreiben!



mal dumm gefragt: warum nicht?
Ich habe gerade in dem Projekt, was ich hier übernehmen musste, noch einige derartige Stellen gefunden ... ;(

Danke und Gruß
Klaus


----------



## Der Müde Joe (6. Jul 2010)

weil "bla" schon einen String erzeugt. und new String("bla") erzeugt aus dem neu erzeugten String einen neuen String


----------



## VfL_Freak (6. Jul 2010)

Moin,



Der Müde Joe hat gesagt.:


> weil "bla" schon einen String erzeugt. und new String("bla") erzeugt aus dem neu erzeugten String einen neuen String



verstehe - Danke.
Ist in meinem Fall eh' nur eine Membervariable einer (älteren) Klasse, die mit "private String m_Text = null;" angelegt wird und nach dem "new String()" aus verschiedenen anderen Klassen heraus mit get- und set-Methoden gefükllt wird.

Hier wäre es wohl sinniger, die Deklaration auf "private String m_Text = "";" umzustellen, oder ??

gruß
Klaus


----------



## Der Müde Joe (6. Jul 2010)

>"new String()" aus verschiedenen anderen Klassen heraus mit get- und set-Methoden gefükllt wird.

Verstehe ich nicht?

Umstellen? m_Text gefällt mir nicht aber sonst..?

EDIT:

```
/**
     * Initializes a newly created {@code String} object so that it represents
     * an empty character sequence.  Note that use of this constructor is
     * unnecessary since Strings are immutable.
     */
    public String() {
	this.offset = 0;
	this.count = 0;
	this.value = new char[0];
    }
```


----------



## Michael... (6. Jul 2010)

VfL_Freak hat gesagt.:


> Hier wäre es wohl sinniger, die Deklaration auf "private String m_Text = "";" umzustellen, oder ??


Warum? Was spricht dagegen eine Variable mit null zu "initialisieren"? Eventuell ist das ja im späteren Programmablauf relevant.


----------



## VfL_Freak (6. Jul 2010)

Michael... hat gesagt.:


> Warum? Was spricht dagegen eine Variable mit null zu "initialisieren"? Eventuell ist das ja im späteren Programmablauf relevant



Nein, das ist es hier wohl nicht, da diese Membervariable (die Klasse stellt eine Art Report zu Verfügung) immer nur gefüllt und ausgelesen, aber nie auf Inhalt, oder besser: auf 'null',  wird!

Eigentlich wird das in diesem Projekt überall so gehandelt, aber ich bin noch in der Einarbeitungphase und habe - dank fehlender Doku - an manchen Stellen noch so meine Verständnisprobleme ..... ;(

Danke und Gruß
Klaus


----------



## SlaterB (6. Jul 2010)

wenn man andere vielleicht komplizierte Projekte übernimmt, dann vorsichtig mit Änderungen, 
in Extremfällen kann new String() schon zum Einsatz kommen,

es reicht wenn man weiß/ beachtet:
solange ich 
String s = "x";
schreiben kann und mir kein triftiger Grund einfällt, sollte ich es unterlassen
String s = new String("x");
zu schreiben


----------



## VfL_Freak (6. Jul 2010)

SlaterB hat gesagt.:


> wenn man andere vielleicht komplizierte Projekte übernimmt, dann vorsichtig mit Änderungen,
> in Extremfällen kann new String() schon zum Einsatz kommen,
> 
> es reicht wenn man weiß/ beachtet:
> ...



ok, Danke .... 

Soweit ich das sehe, wird das "new String()" nur im Konstruktor verwendet und das Objekt wirklich zu instantiieren resp. in einer Reset-Funktion, um die Membervariable zu leeren .....
Ich werde mir das bei Gelegenheit mal in Ruhe im Debugger anschauen müssen ...

[OFFTOPIC]
Wird Hansa (ich vermute mal Rostock) denn DIESES Jahr Meister ???:L
[/OFFTOPIC]

Gruß aus OS
Klaus


----------



## SlaterB (6. Jul 2010)

schon geschehen
F.C. Hansa Rostock ist Deutscher A-Jugend Meister


----------



## VfL_Freak (6. Jul 2010)

SlaterB hat gesagt.:


> schon geschehen
> F.C. Hansa Rostock ist Deutscher A-Jugend Meister



:lol:

stimmt, das habe ich neulich mal im VT gelesen ... Glückwunsch dazu :toll::applaus:

Gemeint hatte ich allerdings eher die neue Drittliga-Saison 
Wünsche euch dafür aber viel Erfolg !!

Gruß
Klaus


----------

