# Tiefen Kopie



## disconnectus (22. Apr 2009)

Die Methode kopie soll eine vollständige Kopie (Tiefenkopie) des aufrufenden Matrix-Objekts
erzeugen und als Ergebnis zurückliefern.


```
Tabelle kopie () {
	
    // liefert eine Tiefen-Kopie zurück

  }
```

Als tabelle haben wir ein Array mit zwei einträge. 

Was heißt das? Was heißt Tiefenkopie?  Wie macht man?

Das ist ein Teil einer Aufgabe.


----------



## Schandro (22. Apr 2009)

Google doch mal nach Deep Copy.


----------



## tfa (22. Apr 2009)

Flache Kopie bedeutet, dass nur die Referenzen auf die  enthaltenen Objekte (hier wohl Arrays) mitkopiert werden.
In einer tiefen Kopie werden die Objekte auch noch selbst kopiert, also z.B. neue Arrays angelegt und deren Elemente kopiert (und die Objekte, die von den Array-Elementen referenziert werden usw.)


----------



## byte (22. Apr 2009)

Tiefe Kopie bedeutet, dass auch alle (mutable) Member des Objekts kopiert werden und deren Member usw.


----------



## disconnectus (22. Apr 2009)

Vielen Dank.


----------



## disconnectus (22. Apr 2009)

Noch eine Frage über kopieren: 

Wie kann man ein Objekt kopieren?


----------



## SlaterB (22. Apr 2009)

Noch eine Antwort zum Kopieren:

durch korrekten Code

edit: dieses und letztes Post waren in einem neuen Thread, hierher kopiert,
dann macht die Frage auch etwas mehr Sinn,
kann aber immer noch ruhig deutlicher werden


----------



## disconnectus (22. Apr 2009)

danke sehr...


----------



## Ebenius (22. Apr 2009)

Die zwei üblichen Konzepte sind: 
überschriebene, öffentliche clone()-Methode
Copy Constructor
Ebenius


----------



## disconnectus (22. Apr 2009)

Das muss ich aber in einer Methode machen.  Geht das durch "öffentliche clone()-Methode" ??


```
public class Tabelle {
............
............

  Tabelle kopie () {

    // liefert eine Tiefen-Kopie des Tabellen-Objekts als Ergebnis zurueck
  }
..........
..........

}
```

Diese methode rufe ich von einer anderen Klasse:

```
public class TabellenTest {
.......
.......
    // Tabelle kopieren in neue Tabelle
    Tabelle tabNeu = tab.kopie();
    System.out.println("Tabelle kopiert");
.......
.......
```


----------



## Ebenius (22. Apr 2009)

Die Methode _kopie()_ ist im Prinzip das gleiche wie eine _clone()_-Methode. Ich hatte so geantwortet, weil du ein neues Thema aufgemacht hast und der Zusammenhang zu diesem Thema (mit _kopie()_-Methode) nicht klar war. Daher hab ich nur allgemein geantwortet.

Wie inhaltlich die Kopie einer Instanz gemacht wird, hängt vom Aufbau der Klasse ab. Das kann man pauschal gar nicht beantwortet. Wie sieht denn die Klasse Tabelle aus die Du da kopieren sollst?

Ebenius


----------



## disconnectus (22. Apr 2009)

Die klasse Tabelle: 

ich habe es selber gemacht, das Program könnte Fehlerhaft sein. 


```
import Prog1Tools.IOTools;

public class Tabelle {
  private double[][] t;  // hier wird die eigentliche Tabelle gespeichert
  double [] zSumme; // hier wird die Summe jeder Zeile gespeichert

  void lies () {
    // liest das Tabellen-Objekt ein
    int zeilen = IOTools.readInteger("Anzahl Zeilen: ");
    t = new double[zeilen][];
    for (int i=0; i < t.length; i++) {
        int spalten = IOTools.readInteger("Anzahl Spalten in Zeile " + i + ": ");
        t[i] = new double[spalten];
        for (int j=0; j < t[i].length; j++)
          t[i][j] = IOTools.readDouble("Wert in Zeile " + i + " und Spalte " + j + ": ");
    }
  }

  double[] zeilenSumme () {
	    // berechnet die Zeilen-Summen des Tabellen-Objekts
	  
	for (int i=0; i < t.length; i++) {
		for (int j=0; j < t[i].length; j++) {
			zSumme [i]= zSumme [i] + t[i][j];
		}
	}
  	  return zSumme;
  }

  void druckeZeile (int k) {
    // gibt die Zeile k des Tabellen-Objekts auf den Bildschirm aus
		for (int j=0; j < t.length; j++) {
				System.out.println (t[k][j] +" ");
		}
  }
  

  void drucke () {
    // gibt das Tabellen-Objekt zeilenweise auf den Bildschirm aus
	  for (int i=0; i < t.length; i++) {
		  druckeZeile (i);
	  }
  }

  Tabelle kopie () {
	  ??????????????????????
          ??????????????????????

	return null;
    // liefert eine Tiefen-Kopie des Tabellen-Objekts als Ergebnis zurueck
  }
}
```


----------



## Ebenius (22. Apr 2009)

Dann musst Du jetzt in der Methode _kopie()_ eine neue Instanz der Tabelle erzeugen, die dann zurück gegeben wird: 
	
	
	
	





```
final Tabelle kopie = new Tabelle();
// hier geht's gleich weiter
return kopie;
```
Dann musst Du alle Variablen der eigenen ebenfalls kopieren. Das könnte so aussehen: 
	
	
	
	





```
if (t != null) {
  kopie.t = new double[t.length][];
  for (int i = 0; i < t.length; i ++) {
    kopie.t[i] = new double[t[i].length];
    System.arraycopy(t[i], 0, kopie.t[i], 0, t[i].length);
  }
}
```
Und so ähnlich musst Du das auch für die zweite Variable _zSumme_ machen. Das kannst Du aber sicher selber.

Hinweis: Mein Quelltext ist im Browser getippt. Kann also gut sein, dass da Fehler drin sind.

Ebenius


----------



## disconnectus (22. Apr 2009)

Vielen Dank... Alles erledigt.


----------



## André Uhres (22. Apr 2009)

disconnectus hat gesagt.:


> Geht das durch "öffentliche clone()-Methode" ?


Ja, etwa so:

```
public class Tabelle implements Cloneable {
...
    public Object clone() throws CloneNotSupportedException {
        Tabelle result = (Tabelle) super.clone();
        if (t != null) {
            result.t = new double[t.length][];
            for (int i = 0; i < t.length; i++) {
                result.t[i] = new double[t[i].length];
                System.arraycopy(t[i], 0, result.t[i], 0, t[i].length);
            }
        }
        if (zSumme != null) {
            result.zSumme = new double[zSumme.length];
            System.arraycopy(zSumme, 0, result.zSumme, 0, zSumme.length);
        }
        return result;
    }
}
```


```
tabelle2 = (Tabelle) tabelle1.clone();
```


----------



## Ebenius (22. Apr 2009)

André, warum nicht einfach so? Das ist wesentlich besser anwendbar. 
	
	
	
	





```
@Override
public Tabelle clone() {
  // der gesamte Body wie Du ihn geschrieben hast
}
```

Ebenius


----------



## André Uhres (23. Apr 2009)

Ebenius hat gesagt.:


> André, warum nicht einfach so? Das ist wesentlich besser anwendbar.
> 
> 
> 
> ...


Weiss ich,  nur wollte ich im Beispiel Java 4 kompatibel bleiben. Ausserdem wirft der Aufruf von super.clone() eine Exception.


----------



## tfa (23. Apr 2009)

André Uhres hat gesagt.:


> Weiss ich,  nur wollte ich im Beispiel Java 4 kompatibel bleiben. Ausserdem wirft der Aufruf von super.clone() eine Exception.



Die Exception kannst du in der Implementierung natürlich weg lassen. Das Cloning wird ja unterstützt, warum also eine CloneNotSupportedException?


----------



## Ebenius (23. Apr 2009)

André Uhres hat gesagt.:


> Ausserdem wirft der Aufruf von super.clone() eine Exception.


Auf keinen Fall, da Cloneable implementiert ist. Also abfangen: 
	
	
	
	





```
try {
  super.clone();
} catch (CloneNotSupportedException ex) {
  assert false;
}
```

Ebenius


----------



## tfa (23. Apr 2009)

Dann doch lieber sicherheitshalber


```
try {
  super.clone();
} catch (CloneNotSupportedException ex) {
  throw new Error("unerwartete CloneNotSupportedException", ex);
}
```

falls asserts nicht aktiviert sind.


----------



## Ebenius (23. Apr 2009)

tfa hat gesagt.:


> Dann doch lieber [...]


Nö. Das ist garantiertes Verhalten der JVM. Das _assert_ steht nur drin, damit im Code klar wird, dass da nicht versehentlich ein leerer catch-Block steht. Aber sicher ist das Geschmackssache.

Ebenius


----------



## maki (23. Apr 2009)

clone() macht mehr Probleme als es löst, Copy-Konstruktoren oder besser gleich Factory Methoden sollten imho bevorzugt werden, falls möglich.


----------



## byte (23. Apr 2009)

Oder per IO:


```
@SuppressWarnings("unchecked")
    public static <T extends Serializable> T copy(T original) {
        ByteArrayOutputStream bos = null;
        ObjectInputStream in = null;
        ObjectOutputStream out = null;
        T obj = null;
        try {
            bos = new ByteArrayOutputStream();
            out = new ObjectOutputStream(bos);
            out.writeObject(original);
            out.flush();
            in = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
            obj = (T) in.readObject();
        }
        catch(IOException e) {
            throw new RuntimeException(e);
        }
        catch(ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        finally {
            Exception ex = null;
            try {
                bos.close();
            } 
            catch (IOException e) {
                ex = e;
            }
            try {
                out.close();
            }
            catch (IOException e) {
                ex = e;
            }
            try {
                in.close();
            }
            catch (IOException e) {
                ex = e;
            }
            if (ex != null) {
                throw new RuntimeException(ex);
            }
        }
        
        return obj;
    }
```


----------



## Ebenius (23. Apr 2009)

maki hat gesagt.:


> clone() macht mehr Probleme als es löst, Copy-Konstruktoren oder besser gleich Factory Methoden sollten imho bevorzugt werden, falls möglich.


Die Aussage ist sehr pauschal und deshalb falsch. Es kommt wie immer auf den Anwendungsfall an. Wenn meine Objekte bspw. so aussehen: 
	
	
	
	





```
abstract class Node {

  @Override
  public abstract Node clone();
}

class Element extends Node {

  private final String name;

  /** Creates a new {@code Element}. */
  public Element(String name) {
    this.name = name;
  }

  @Override
  public Element clone() {
    return new Element(this.name);
  }
}

class Comment extends Node {

  private final String text;

  /** Creates a new <code>Comment</code>. */
  public Comment(String text) {
    this.text = text;
  }

  @Override
  public Comment clone() {
    return new Comment(this.text);
  }
}
```
... und ein Kontainer mit Elementen kopiert werden soll, dann ist _clone()_ eine super Lösung: 
	
	
	
	





```
for (Node n : container) {
  containerCopy.add(n.clone());
}
```
Wieso ist das schlecht? Was wäre hier besser?

Ebenius


----------



## tfa (23. Apr 2009)

Ebenius hat gesagt.:


> Nö. Das ist garantiertes Verhalten der JVM. Das _assert_ steht nur drin, damit im Code klar wird, dass da nicht versehentlich ein leerer catch-Block steht. Aber sicher ist das Geschmackssache.


Solange die Klasse direkt von Object abgeleitet ist. Aber wehe, jemand refactort eine Oberklasse heraus und super.clone() wirft plötzlich die Exception...


----------



## maki (23. Apr 2009)

> Wieso ist das schlecht? Was wäre hier besser?


Sobald ein final Feld vorkommt welches initialisert wird, kommt man mit clone nicht weiter, denn clone hat nicht diesselben Möglichkeiten wie ein Konstruktor.

Wenn du nicht die "echte" clone Methode überschreibst sondern eine eigene nimmst, wie hier zB.:

```
@Override
  public abstract Node clone();
```
könntest du ja auch gleich den ganzen Schritt machen und eine eigene factory Methode/Copy konstruktor anbieten 

Andersrum gesagt, du nutzt/überschreibst gar nicht die Object.clone() Methode (wahrscheinlich wegen ihrer "schrägheit"), sondern machst schon deine eigene Factory Methode, nur solltst du dass auch mit einem anderen Namen ausdrücken 

Das "original" clone() ist 'ne Missgeburt, Bloch hat darüber ein ganzes Kapitel verfasst: Josh Bloch on Design


----------



## tfa (23. Apr 2009)

@maki: Wieso? Er überschreibt doch die "original" clone Methode. Kovarianz gibt es ab Java 5 (?). Sonst würde das @Override doch nicht funktionieren. Oder was meinst du?


----------



## Ebenius (23. Apr 2009)

tfa hat gesagt.:


> Solange die Klasse direkt von Object abgeleitet ist. Aber wehe, jemand refactort eine Oberklasse heraus und super.clone() wirft plötzlich die Exception...


Das wäre sehr verboten. Die API-Doc von CloneNotSupportedException sagt explizit, dass die Exception nur dann geworfen werden darf, wenn die _clone()_-Methode der Klasse Object aufgerufen wurde und Cloneable nicht implementiert wird. 





			
				API-Doc::CloneNotSupportedException hat gesagt.:
			
		

> Thrown to indicate that the clone method in class Object has been called to clone an object, but that the object's class does not implement the Cloneable interface.


Ebenius


----------



## byte (23. Apr 2009)

Ebenius hat gesagt.:


> Wieso ist das schlecht? Was wäre hier besser?



Siehe z.B.: How to avoid traps and correctly override methods from java.lang.Object - JavaWorld


----------



## tfa (23. Apr 2009)

Ebenius hat gesagt.:


> Das wäre sehr verboten. Die API-Doc von CloneNotSupportedException sagt explizit, dass die Exception nur dann geworfen werden darf, wenn die _clone()_-Methode der Klasse Object aufgerufen wurde und Cloneable nicht implementiert wird.


Du musst schon weiter lesen:



> Applications that override the <code>clone</code> method can also
> throw this exception to indicate that an object could not or
> should not be cloned.



Was ich eigentlich sagen wollte: Es ist praktisch immer schlecht (auch hier), Exceptions einfach so zu verschlucken. Auch wenn man sich sicher ist, dass sie nie auftreten können. Im Zweifel wirf man halt einen Error.


----------



## Ebenius (23. Apr 2009)

maki hat gesagt.:


> Sobald ein final Feld vorkommt welches initialisert wird, kommt man mit clone nicht weiter, denn clone hat nicht diesselben Möglichkeiten wie ein Konstruktor.


Wie der Inhalt der _clone()_-Methode aussieht bestimmt die Klasse die sie implementiert. Wenn _final_ Members benutzt werden sollen, dann kann man aus der _clone()_-Methode super den Copy-Konstruktor aufrufen. Die Kombination aus beidem halte ich ohnehin oft für sinnvoll. Das spricht aber doch nicht gegen die _clone()_-Methode als Bestandteil meiner API.



maki hat gesagt.:


> Wenn du nicht die "echte" clone Methode überschreibst sondern eine eigene nimmst, wie hier zB.:
> 
> ```
> @Override
> ...


Was? Ich überschreibe doch die Object.clone()-Methode. Genau die. Und keine andere.



maki hat gesagt.:


> [...] könntest du ja auch gleich den ganzen Schritt machen und eine eigene factory Methode/Copy konstruktor anbieten



Dann erkläre mir doch mal anhand meines Beispiels, wie die Schleife oder die Factory wissen soll, welche genaue Implementierung jetzt kopiert werden soll. Genau das ist der Vorteil der _clone()_-Methode (wie auch immer sie heißt), dass der Caller nicht wissen muss, welche genaue Implementierung kopiert wird.



maki hat gesagt.:


> Das "original" clone() ist 'ne Missgeburt, Bloch hat darüber ein ganzes Kapitel verfasst: Josh Bloch on Design


In diesem Punkt sind wir einer Meinung. Der Field-by-Field-Copy-Mechanismus der Object._clone()_-Implementierung ist ein Verbrechen und ich bin dankbar, dass die Methode in Object nicht _public_ ist.

Ebenius


----------



## Ebenius (23. Apr 2009)

tfa hat gesagt.:


> Du musst schon weiter lesen: [...] Es ist praktisch immer schlecht (auch hier), Exceptions einfach so zu verschlucken. Auch wenn man sich sicher ist, dass sie nie auftreten können. Im Zweifel wirf man halt einen Error.


Der Punkt geht an Dich; hast ihn Dir verdient.  Also lieber _Error_ werfen.

Ebenius


----------



## André Uhres (23. Apr 2009)

Ebenius hat gesagt.:


> Auf keinen Fall, da Cloneable implementiert ist.


Ich wollte eigentlich nur sagen, daß man sich um die Exception kümmern muss, falls man sie, wie in deinem Vorschlag, nicht wirft (sei es original oder abgewandelt):


Ebenius hat gesagt.:


> ```
> @Override
> public Tabelle clone() {
> // der gesamte Body wie Du ihn geschrieben hast
> ...


----------



## Ebenius (23. Apr 2009)

André Uhres hat gesagt.:


> Ich wollte eigentlich nur sagen, daß man sich um die Exception kümmern muss, falls man sie, wie in deinem Vorschlag, nicht wirft (sei es original oder abgewandelt):


Ertappt. Ich hab's zweimal durchgelesen und den super-Aufruf einfach übersehen. War einfach nicht aufmerksam genug. Ich bin für abfangen und (inzwischen nachdem ich überzeugt wurde) Error werfen, falls CloneNotSupportedException auftaucht.

Ebenius


----------



## André Uhres (24. Apr 2009)

Ein einfaches "du hast recht" hätte genügt :lol:


----------



## Spacerat (24. Apr 2009)

Ich frage mich gerade, ob man nicht wieder irgendeinen "Contract" verletzt, wenn man mit "clone()" irgend etwas kopiert. Wenn nicht, wird's Zeit, für einen diesbezüglichen "Contract". Klonen und Kopieren sind doch zwei verschiedene Dinge. Beim Klonen werden einfach die Referenzen der Member der neuen Instanz übergeben während beim Kopieren neue Instanzen der Member erzeugt.


----------



## André Uhres (25. Apr 2009)

Spacerat hat gesagt.:


> Ich frage mich gerade, ob man nicht wieder irgendeinen "Contract" verletzt, wenn man mit "clone()" irgend etwas kopiert.


Der "Contract" für die clone Methode ist schwach.
Hier ist der "Contract", kopiert aus der Spezifikation für java.lang.Object (nach Bloch):

clone() creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object. The general intent is that, for any object x, the expression

```
x.clone() != x
```
will be true, and the expression

```
x.clone().getClass() == x.getClass()
```
will be true, but these are not absolute requirements. While it is typically the case that

```
x.clone().equals(x)
```
will be true, this is not an absolute requirement. Copying an object will typically entail creating a new instance of its class, but it may require copying of internal data structures as well. No constructors are called.

BEMERKUNGEN nach Bloch: 
The provision that "no constructors are called" is too strong.
The provision that x.clone().getClass() should generally be identical to x.getClass(), however, is too weak. 
The Cloneable interface does not, as of Release 1.3, spell out the responsibilities that a class takes on when it implements this interface.


----------

