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:
ArrayList<A> list1;
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:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(new A(a));
}
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:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
if(a instanceof A) {
list2.add(new A(a));
} else if(a instanceof B) {
list2.add(new B(a));
} else if(a instanceof C) {
list2.add(new C(a));
}
}
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:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(a.clone());
}
Viele Leute haben angegeben, warum die grundlegende Java-Implementierung von Klonen problematisch ist. Aber es ist leicht so zu überwinden:
In Klasse A:
public A clone() {
return new A(this);
}
In Klasse B:
@Override
public B clone() {
return new B(this);
}
In Klasse C:
@Override
public C clone() {
return new C(this):
}
Ich implementiere Cloneable nicht, sondern verwende nur denselben Funktionsnamen. Wenn Ihnen das nicht gefällt, nennen Sie es etwas anderes.