{"id":2242,"date":"2013-09-03T21:14:39","date_gmt":"2013-09-03T19:14:39","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/?p=2242"},"modified":"2013-09-03T21:14:39","modified_gmt":"2013-09-03T19:14:39","slug":"tiefe-objektkopien-deep-copy","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2013\/09\/tiefe-objektkopien-deep-copy\/","title":{"rendered":"Tiefe Objektkopien (Deep Copy)"},"content":{"rendered":"<p>Die clone() Methode liefert nur flache Kopien eines Objektes. Mit Hilfe der Serialisierung kommt man schnell auch zu tiefen Kopien. Klassen k\u00f6nnen die <b>clone()<\/b> Methode von <b>Object<\/b> \u00fcberschreiben und so eine Kopie der Werte liefern. Die Standardimplementierung ist jedoch so angelegt, dass diese Kopie flach ist, was bedeutet, Referenzen auf Objekte die von dem zu klonenden Objekt ausgehen, werden beibehalten und diese Objekte nicht extra kopiert. Als Beispiel kann die einfache Datenstruktur eines Feldes gen\u00fcgen, welches auf <b>Vector<\/b> Objekte verweiset. Eine Klon dieses Feldes ist lediglich ein zweites Feld, dessen Elemente auf die gleichen Vektoren zeigen. Eine \u00c4nderung wird also beiden Felder bewusst.<\/p>\n<p>M\u00f6chten wir das Verhalten \u00e4ndern und eine tiefe Kopie anfertigen, so haben wir mit einem kleinen Trick keine M\u00fche damit. Die Idee ist, dass wir das zu klonende Objekt einfach Serialisieren und dann wieder auspacken. Die zu klonenden Objekte m\u00fcssen dann nur das <b>Serializable<\/b> Interface implementieren.<\/p>\n<pre>public static Object deepCopy( Object o ) throws Exception\n{\n  ByteArrayOutputStream baos = new ByteArrayOutputStream();\n  new ObjectOutputStream( baos ).writeObject( o );\n\n  ByteArrayInputStream bais = new ByteArrayInputStream( baos.toByteArray() );\n\n  return new ObjectInputStream(bais).readObject();\n}<\/pre>\n<p>Das einzige was wir zum Gelingen der Methode <b>deepCopy()<\/b> machen m\u00fcssen, ist das Objekt in ein Bytefeld zu serialisieren und dann wieder auszulesen und zu einem Objekt konvertieren. Den Einsatz eines <b>ByteArrayOutputStream<\/b> haben wir schon gesehen, als wir die L\u00e4nge eines Objektes herausfinden wollten. Nur f\u00fcgen wir nun das Feld wieder einem <b>ByteArrayInputStream<\/b> zu, aus dessen Daten dann der <b>ObjectInputStream<\/b> wieder das Objekt rekreieren kann.<\/p>\n<p>\u00dcberzeugen wir uns an Hand eines kleines Programms, dass die tiefe Kopie tats\u00e4chlich etwas anderes als ein <b>clone()<\/b> ist. (Verwendet werden Raw-Types um das Bsp. kurz zu halten.)<\/p>\n<pre>public static void main( String args[] ) throws Exception\n{\n  Map map = new HashMap() {{\n    put( &quot;Cul de Paris&quot;, &quot;hinten unter dem Kleid getragenes Gestell oder Polster&quot; );\n  }};\n\n  LinkedList l1 = new LinkedList(); \n  l1.add( map );\n\n  List l2 = (List) l1.clone();\n\n  List l3 = (List) deepCopy( l1 );\n\n  map.clear();\n\n  System.out.println( l1 );\n  System.out.println( l2 );\n  System.out.println( l3 );\n}<\/pre>\n<p>Zun\u00e4chst erstellen wir eine Map, die wie anschie\u00dfend in eine Liste packen. Die Map enth\u00e4lt ein P\u00e4rchen. Klonen wir mit <b>clone() <\/b>die Liste, so wird zwar die Liste selbst kopiert, aber nicht die Map. Die tiefe Kopie kopiert neben der Liste auch gleich die Map mit. Das sehen wir dann, wenn wir den Eintrag aus dem Map l\u00f6schen. Dann ergibt l1 genauso wie l2 eine leere Liste, da l2 zur die Verweise auf die Map gespeichert hat, die dann aber geleert ist. Anders ist dies bei l3, der tiefen Kopie; hier ist das Paar noch vorhanden. Die Ausgabe ist dann:<\/p>\n<pre>[{}]\n[{}]\n[{Cul de Paris=hinten unter dem Kleid getragenes Gestell...}]<\/pre>\n<p>An diesem Beispiel sehen wir, wie wunderbar die Stream-Klassen zusammenarbeiten. Einzige Voraussetzung zum Gelingen ist die Implementierung der Schnittstelle <b>Serializable<\/b>. Da aber die zu klonenden Klassen auch <b>clone()<\/b> implementieren m\u00fcssen, gilt in der Regel, dass sie serialisierbar sind. Daher steht in der implements Zeile die Schnittstelle <b>Clonable<\/b> und <b>Serializable<\/b> direkt nebeneinander.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Die clone() Methode liefert nur flache Kopien eines Objektes. Mit Hilfe der Serialisierung kommt man schnell auch zu tiefen Kopien. Klassen k\u00f6nnen die clone() Methode von Object \u00fcberschreiben und so eine Kopie der Werte liefern. Die Standardimplementierung ist jedoch so angelegt, dass diese Kopie flach ist, was bedeutet, Referenzen auf Objekte die von dem zu [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[1],"tags":[],"class_list":["post-2242","post","type-post","status-publish","format-standard","hentry","category-allgemein"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/2242","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/comments?post=2242"}],"version-history":[{"count":1,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/2242\/revisions"}],"predecessor-version":[{"id":2243,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/2242\/revisions\/2243"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=2242"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=2242"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=2242"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}