voc*_*aro 7 java clone deep-copy copy-constructor cloneable
我有一些代码使用Object.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());
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用复制构造函数的深层复制
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());
}
}
}
Run Code Online (Sandbox Code Playgroud)
我觉得有趣的是,尽管所有关于Java中克隆的邪恶的讨论,克隆替代方案需要更少的代码和更少的演员表(至少在这种情况下).
我很感激复制构造函数的反馈.你会以不同的方式做到吗?谢谢.
代替:
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
Run Code Online (Sandbox Code Playgroud)
我更喜欢:
public Person clone() {
try {
return (Person) clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException("This should be impossible ...");
}
}
Run Code Online (Sandbox Code Playgroud)
因此调用者不必处理永远不会发生的异常,也不必进行强制转换。
在复制构造函数方法中,可以更好地以多态方式处理类型切换:
abstract class Person {
...
public abstract Person deepCopy();
}
class Student {
...
public Student deepCopy() {
return new Student(this);
}
}
class Teacher {
...
public Teacher deepCopy() {
return new Teacher(this);
}
}
Run Code Online (Sandbox Code Playgroud)
现在编译器可以检查您是否为所有子类型提供了深层复制,并且您不需要任何强制转换。
最后,请注意,克隆和复制构造函数方法都具有相同的公共 api(该方法是否被调用clone()并不deepCopy()重要),因此您使用哪种方法是实现细节。复制构造函数方法更加冗长,因为您提供了构造函数和调用该构造函数的方法,但它可以更容易地推广到通用类型转换工具,允许执行以下操作:
public Teacher(Person p) {
...
say("Yay, I got a job");
}
Run Code Online (Sandbox Code Playgroud)
建议:如果您只需要相同的副本,请使用克隆;如果您的调用者可能希望请求特定类型的实例,请使用复制构造函数。
| 归档时间: |
|
| 查看次数: |
16159 次 |
| 最近记录: |