Ho un codice che esegue una copia profonda utilizzando Object.clone, ma sto tentando di riscriverlo utilizzando la tecnica di costruzione di copia più "accettabile". Di seguito sono riportati due semplici esempi di ciò che sto cercando di fare, il primo che utilizza il clone e il secondo che utilizza un costruttore di copie.Modo corretto per eseguire una copia approfondita con il costruttore di copia anziché Object.clone
profonda copia utilizzando clone
import java.util.*;
abstract class Person implements Cloneable {
String name;
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Teacher extends Person implements Cloneable {
int courses;
public String toString() { return name + ": courses=" + courses; }
}
class Student extends Person implements Cloneable {
double gpa;
public String toString() { return name + ": gpa=" + gpa; }
}
public class DeepCopy_Clone {
private static List<Person> deepCopy(List<Person> people) throws CloneNotSupportedException {
List<Person> copy = new ArrayList<Person>();
for (Person person : people) {
copy.add((Person)person.clone());
}
return copy;
}
public static void main(String[] args) throws CloneNotSupportedException {
ArrayList<Person> people = new ArrayList<Person>();
Teacher teacher = new Teacher();
teacher.name = "Teacher";
teacher.courses = 5;
people.add(teacher);
Student student = new Student();
student.name = "Student";
student.gpa = 4.0;
people.add(student);
List<Person> peopleCopy = deepCopy(people);
// Invalidate the original data to prove a deep copy occurred
teacher.name = null;
teacher.courses = -1;
student.name = null;
student.gpa = -1;
for (Person person : peopleCopy) {
System.out.println(person.toString());
}
}
}
profonda copia utilizzando costruttore di copia
import java.util.*;
abstract class Person {
String name;
public Person() {}
public Person(Person other) {
this.name = other.name;
}
public Person deepCopy() {
if (this instanceof Teacher) {
return new Teacher((Teacher)this);
} else if (this instanceof Student) {
return new Student((Student)this);
}
throw new Error("Unknown type of person");
}
}
class Teacher extends Person {
int courses;
public Teacher() {}
public Teacher(Teacher other) {
super(other);
this.courses = other.courses;
}
public String toString() { return name + ": courses=" + courses; }
}
class Student extends Person {
double gpa;
public Student() {}
public Student(Student other) {
super(other);
this.gpa = other.gpa;
}
public String toString() { return name + ": gpa=" + gpa; }
}
public class DeepCopy_ConstructorAlternative {
private static List<Person> deepCopy(List<Person> people) {
List<Person> copy = new ArrayList<Person>();
for (Person person : people) {
copy.add(person.deepCopy());
}
return copy;
}
public static void main(String[] args) {
ArrayList<Person> people = new ArrayList<Person>();
Teacher teacher = new Teacher();
teacher.name = "Teacher";
teacher.courses = 5;
people.add(teacher);
Student student = new Student();
student.name = "Student";
student.gpa = 4.0;
people.add(student);
List<Person> peopleCopy = deepCopy(people);
// Invalidate the original data to prove a deep copy occurred
teacher.name = null;
teacher.courses = -1;
student.name = null;
student.gpa = -1;
for (Person person : peopleCopy) {
System.out.println(person.toString());
}
}
}
Quello che trovo interessante è che, nonostante tutti i discorsi sui mali della clonazione in Java, il l'alternativa al clone richiede meno codice e meno cast (in questo caso particolare, almeno).
Apprezzerei il feedback sull'alternativa del costruttore di copie. Lo faresti diversamente? Grazie.
Dimenticare o non essere in grado di aggiornare Person.deepCopy non sono problemi al confronto. Cioè, puoi affrontare problemi molto simili con l'alternativa clone. Ad esempio, se qualcuno crea una nuova "classe Administrator extends Person", dovrà ricordarsi di implementare Administrator.clone (assumendo che una copia field-by-field non esegua una copia profonda). Non essere in grado di aggiornare Person.deepCopy può essere gestito sovrascrivendolo nella sottoclasse. E sì, devi ricordarti di farlo, ma ancora una volta è lo stesso problema con l'alternativa clona. – vocaro