Tiefen Kopie

Status
Nicht offen für weitere Antworten.

disconnectus

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

Java:
  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.
 
Zuletzt bearbeitet:

tfa

Top Contributor
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

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

SlaterB

Gast
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
 
Zuletzt bearbeitet von einem Moderator:

disconnectus

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

Java:
public class Tabelle {
............
............

  Tabelle kopie () {

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

}

Diese methode rufe ich von einer anderen Klasse:
Java:
public class TabellenTest {
.......
.......
    // Tabelle kopieren in neue Tabelle
    Tabelle tabNeu = tab.kopie();
    System.out.println("Tabelle kopiert");
.......
.......
 
Zuletzt bearbeitet:

Ebenius

Top Contributor
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

Aktives Mitglied
Die klasse Tabelle:

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

Java:
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
  }
}
 
Zuletzt bearbeitet:

Ebenius

Top Contributor
Dann musst Du jetzt in der Methode kopie() eine neue Instanz der Tabelle erzeugen, die dann zurück gegeben wird:
Java:
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:
Java:
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
 

André Uhres

Top Contributor
Geht das durch "öffentliche clone()-Methode" ?
Ja, etwa so:
Java:
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;
    }
}
Java:
tabelle2 = (Tabelle) tabelle1.clone();
 

Ebenius

Top Contributor
André, warum nicht einfach so? Das ist wesentlich besser anwendbar.
Java:
@Override
public Tabelle clone() {
  // der gesamte Body wie Du ihn geschrieben hast
}

Ebenius
 

André Uhres

Top Contributor
André, warum nicht einfach so? Das ist wesentlich besser anwendbar.
Java:
@Override
public Tabelle clone() {
  // der gesamte Body wie Du ihn geschrieben hast
}
Weiss ich, nur wollte ich im Beispiel Java 4 kompatibel bleiben. Ausserdem wirft der Aufruf von super.clone() eine Exception.
 

tfa

Top Contributor
Dann doch lieber sicherheitshalber

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

falls asserts nicht aktiviert sind.
 
M

maki

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

byte

Top Contributor
Oder per IO:

Java:
    @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

Top Contributor
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:
Java:
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:
Java:
for (Node n : container) {
  containerCopy.add(n.clone());
}
Wieso ist das schlecht? Was wäre hier besser?

Ebenius
 

tfa

Top Contributor
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...
 
M

maki

Gast
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.:
Java:
  @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

Top Contributor
@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

Top Contributor
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
 

tfa

Top Contributor
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

Top Contributor
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.

Wenn du nicht die "echte" clone Methode überschreibst sondern eine eigene nimmst, wie hier zB.:
Java:
  @Override
  public abstract Node clone();
Was? Ich überschreibe doch die Object.clone()-Methode. Genau die. Und keine andere.

[...] 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.

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

Top Contributor
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
 

Ebenius

Top Contributor
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
 
S

Spacerat

Gast
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

Top Contributor
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
Code:
x.clone() != x
will be true, and the expression
Code:
x.clone().getClass() == x.getClass()
will be true, but these are not absolute requirements. While it is typically the case that
Code:
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.
 
Zuletzt bearbeitet:
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
K Tiefen- und Breitensuche beim Baum durch Stack und Warteschlange Java Basics - Anfänger-Themen 1
J Tiefen-, Breitensuche Java Basics - Anfänger-Themen 4
C Kopie oder Referenz ? Java Basics - Anfänger-Themen 5
L Tiefe Kopie einer Zeile eines zweidimensionalen Arrays Java Basics - Anfänger-Themen 1
P Datentypen LinkedList: Kopie behält Referenz? Java Basics - Anfänger-Themen 3
X Kopierkonstruktor / tiefe Kopie Java Basics - Anfänger-Themen 3
V Tiefe Kopie Java Basics - Anfänger-Themen 3
Furtano OOP Memento Pattern | übergabe einer Kopie des Arrays Java Basics - Anfänger-Themen 0
S Klassen Tiefe Kopie mittels Kopierkonstruktor Java Basics - Anfänger-Themen 6
GianaSisters ArrayList-Kopie verändert Original Java Basics - Anfänger-Themen 5
P Kopie erstellen / addieren von Arrays Java Basics - Anfänger-Themen 5
? clonen -tiefe Kopie Java Basics - Anfänger-Themen 6
N Kopie eines Objektes, die Objekt beeinflusst? Java Basics - Anfänger-Themen 6
P Objekte als Attribut: Referenz oder Kopie? Java Basics - Anfänger-Themen 3
S Array Kopie zwei in eindimensionales feld Java Basics - Anfänger-Themen 4
G Parameterübergabe als Referenz bzw. als Kopie Java Basics - Anfänger-Themen 4
F 1:1 kopie möglichst effektiv und schnell Java Basics - Anfänger-Themen 7
M Kopie eines Objektes Java Basics - Anfänger-Themen 8
G Rückgabe einer Kopie bzw. Referenz Java Basics - Anfänger-Themen 22
C Kopie einer ArrayList: Fehler im Detail? Java Basics - Anfänger-Themen 2
L Referenz vs. Kopie Java Basics - Anfänger-Themen 2
R Kopie erzeugen Java Basics - Anfänger-Themen 2

Ähnliche Java Themen

Neue Themen


Oben