Ich habe nach Tutorials gesucht, die Java erklären Cloneable
, aber keine guten Links erhalten, und Stack Overflow wird sowieso immer offensichtlicher.
Ich würde gerne folgendes wissen:
Cloneable
bedeutet, dass wir einen Klon oder eine Kopie von Objekten haben können, indem wir dieCloneable
Schnittstelle implementieren . Was sind die Vor- und Nachteile davon?- Wie erfolgt das rekursive Klonen, wenn das Objekt ein zusammengesetztes Objekt ist?
Antworten:
Das erste, was Sie wissen sollten,
Cloneable
ist - verwenden Sie es nicht.Es ist sehr schwer, das Klonen mit
Cloneable
Recht zu implementieren , und der Aufwand lohnt sich nicht.Verwenden Sie stattdessen einige andere Optionen, wie Apache-Commons
SerializationUtils
(Deep-Clone) oderBeanUtils
(Flach-Clone), oder verwenden Sie einfach einen Kopierkonstruktor.Hier finden Sie die Ansichten von Josh Bloch zum Klonen mit
Cloneable
, was die vielen Nachteile des Ansatzes erklärt. ( Joshua Bloch war ein Sun-Mitarbeiter und leitete die Entwicklung zahlreicher Java-Funktionen.)quelle
static
methoden in schnittstellen haben, also einfach einstatic WhatEverTheInterface copy(WhatEverTheInterface initial)
? Aber ich frage mich, was Ihnen das bringt, da Sie beim Klonen Felder von einem Objekt kopieren, aber eine Schnittstelle nur Methoden definiert. Möchtest du das erklären?Cloneable selbst ist leider nur eine Marker-Schnittstelle, das heißt: Es definiert nicht die clone () -Methode.
Dadurch wird das Verhalten der geschützten Object.clone () -Methode geändert, wodurch eine CloneNotSupportedException für Klassen ausgelöst wird, die Cloneable nicht implementieren, und für Klassen, die dies tun, eine flache Kopie in Bezug auf die Mitglieder durchgeführt wird.
Auch wenn dies das Verhalten ist, nach dem Sie suchen, müssen Sie Ihre eigene clone () -Methode implementieren, um es öffentlich zu machen.
Wenn Sie Ihren eigenen clone () implementieren, sollten Sie mit dem von super.clone () erstellten Objekt beginnen, das garantiert zur richtigen Klasse gehört, und dann eine zusätzliche Population von Feldern ausführen, falls eine flache Kopie nicht der Fall ist Sie wollen. Das Aufrufen eines Konstruktors von clone () wäre problematisch, da dies die Vererbung unterbrechen würde, falls eine Unterklasse ihre eigene zusätzliche klonbare Logik hinzufügen möchte. Wenn es super.clone () aufrufen würde, würde es in diesem Fall ein Objekt der falschen Klasse erhalten.
Dieser Ansatz umgeht jedoch jede Logik, die in Ihren Konstruktoren definiert ist und möglicherweise problematisch sein kann.
Ein weiteres Problem besteht darin, dass alle Unterklassen, die vergessen haben, clone () zu überschreiben, automatisch die flache Standardkopie erben, was im Falle eines veränderlichen Status (der jetzt zwischen der Quelle und der Kopie geteilt wird) wahrscheinlich nicht das ist, was Sie wollen.
Die meisten Entwickler verwenden Cloneable aus diesen Gründen nicht und implementieren stattdessen einfach einen Kopierkonstruktor.
Für weitere Informationen und mögliche Fallstricke von Cloneable empfehle ich das Buch Effective Java von Joshua Bloch
quelle
Verwenden Sie Cloneable also mit Bedacht. Es bietet Ihnen nicht genügend Vorteile im Vergleich zu dem Aufwand, den Sie aufwenden müssen, um alles richtig zu machen.
quelle
Das Klonen ist ein grundlegendes Programmierparadigma. Die Tatsache, dass Java es in vielerlei Hinsicht schlecht implementiert hat, verringert keineswegs die Notwendigkeit des Klonens. Und es ist einfach, das Klonen zu implementieren, das funktioniert, wie Sie möchten, flach, tief, gemischt, was auch immer. Sie können sogar den Namensklon für die Funktion verwenden und Cloneable nicht implementieren, wenn Sie möchten.
Angenommen, ich habe Klassen A, B und C, wobei B und C von A abgeleitet sind. Wenn ich eine Liste von Objekten vom Typ A wie folgt habe:
Diese Liste kann nun Objekte vom Typ A, B oder C enthalten. Sie wissen nicht, um welchen Typ es sich bei den Objekten handelt. Sie können die Liste also nicht wie folgt kopieren:
Wenn das Objekt tatsächlich vom Typ B oder C ist, erhalten Sie nicht die richtige Kopie. Und was ist, wenn A abstrakt ist? Nun haben einige Leute dies vorgeschlagen:
Das ist eine sehr, sehr schlechte Idee. Was ist, wenn Sie einen neuen abgeleiteten Typ hinzufügen? Was ist, wenn B oder C in einem anderen Paket enthalten sind und Sie in dieser Klasse keinen Zugriff darauf haben?
Was Sie tun möchten, ist Folgendes:
Viele Leute haben angegeben, warum die grundlegende Java-Implementierung von Klonen problematisch ist. Aber es ist leicht so zu überwinden:
In Klasse A:
In Klasse B:
In Klasse C:
Ich implementiere Cloneable nicht, sondern verwende nur denselben Funktionsnamen. Wenn Ihnen das nicht gefällt, nennen Sie es etwas anderes.
quelle
A) Es gibt nicht viele Vorteile des Klons gegenüber einem Kopierkonstruktor. Das wahrscheinlich größte ist die Möglichkeit, ein neues Objekt mit genau demselben dynamischen Typ zu erstellen (vorausgesetzt, der deklarierte Typ ist klonbar und verfügt über eine öffentliche Klonmethode).
B) Der Standardklon erstellt eine flache Kopie und bleibt eine flache Kopie, es sei denn, Ihre Klonimplementierung ändert dies. Dies kann schwierig sein, insbesondere wenn Ihre Klasse Abschlussfelder hat
Bozho hat recht, Klon kann schwierig sein, richtig zu machen. Ein Kopierkonstruktor / eine Kopierfabrik erfüllt die meisten Anforderungen.
quelle
Was sind die Nachteile von Cloneable?
Das Klonen ist sehr gefährlich, wenn das Objekt, das Sie kopieren, eine Komposition aufweist. In diesem Fall müssen Sie über mögliche Nebenwirkungen nachdenken, da das Klonen eine flache Kopie erstellt:
Angenommen, Sie haben ein Objekt für die Manipulation im Zusammenhang mit der Datenbank. Angenommen, dieses Objekt hat ein
Connection
Objekt als eine der Eigenschaften.Wenn also jemand einen Klon
originalObject
erstellt, sagen wir, das Objekt, das erstellt wirdcloneObject
. Hier dieoriginalObject
undcloneObject
halten die gleiche Referenz fürConnection
Objekt.Angenommen,
originalObject
dasConnection
Objekt wird geschlossen, sodass dercloneObject
Wille jetzt nicht mehr funktioniert, da dasconnection
Objekt zwischen ihnen geteilt und von der tatsächlich geschlossen wurdeoriginalObject
.Ein ähnliches Problem kann auftreten, wenn Sie beispielsweise ein Objekt klonen möchten, dessen Eigenschaft IOStream ist.
Wie erfolgt das rekursive Klonen, wenn das Objekt ein zusammengesetztes Objekt ist?
Cloneable führt eine flache Kopie durch. Dies bedeutet, dass Daten des Originalobjekts und des Klonobjekts auf dieselbe Referenz / denselben Speicher verweisen. Im Gegensatz dazu werden im Fall einer tiefen Kopie Daten aus dem Speicher des ursprünglichen Objekts in den Speicher des Klonobjekts kopiert.
quelle
Cloneable
führt keine Kopie durch,Object.clone
tut es. "Daten aus dem Speicher des Originalobjekts werden in den Speicher des Klonobjekts kopiert" ist genau das, wasObject.clone
funktioniert. Sie müssen über den Speicher von referenzierten Objekten sprechen, um das tiefe Kopieren zu beschreiben.