使用复制构造函数而不是Object.clone进行深层复制的正确方法 [英] Proper way to deep copy with copy constructor instead of Object.clone

查看:115
本文介绍了使用复制构造函数而不是Object.clone进行深层复制的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些使用Object.clone执行深层复制的代码,但我正在尝试使用更可接受的复制构造函数来重写它。下面是我正在尝试做的两个简单示例,第一个使用克隆,第二个使用复制构造函数。

I have some code that performs a deep copy using Object.clone, but I'm trying to rewrite it using the more "acceptable" copy constructor technique. Below are two simple examples of what I'm trying to do, the first using clone and the second using a copy constructor.

使用克隆的深层复制

 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());
         }
     }
 }

使用深层复制复制构造函数

 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());
         }
     }
 }

我觉得有趣的是尽管所有关于Java中克隆的邪恶的讨论,克隆替代方案需要更少的代码和更少的演员表(至少在这种情况下)。

What I find interesting is that despite all the talk about the evils of cloning in Java, the clone alternative requires less code and fewer casts (in this particular case, at least).

我很感激关于复制构造函数替代的反馈。你会以不同的方式做到吗?谢谢。

I'd appreciate feedback on the copy constructor alternative. Would you do it any differently? Thanks.

推荐答案

而不是:

 public Object clone() throws CloneNotSupportedException {
     return super.clone();
 }

我更喜欢:

public Person clone() {
    try {
        return (Person) clone();
    } catch (CloneNotSupportedException e) {
        throw new RuntimeException("This should be impossible ...");
    }
}

因此调用者不必处理异常永远不会发生,也不必抛出。

so callers don't have to handle an exception that can never occur, and don't have to cast.

在复制构造方法中,类型切换可以更好地处理多态:

In the copy-constructor approach, the type switching is better handled polymorphically:

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);
    }
}

现在编译器可以检查你是否提供了深拷贝对于所有子类型,并且您不需要任何强制类型转换。

now the compiler can check that you have provided deep copy for all subtypes, and you don't need any casts.

最后,请注意克隆和复制构造方法都具有相同的公共API(无论方法是否为调用 clone() deepCopy()并不重要,所以你使用哪种方法是一个实现细节。复制构造函数方法更详细,因为您提供了构造函数和调用该构造函数的方法,但它可以更容易地推广到通用类型转换工具,允许以下内容:

Finally, note that both the cloning and copy-constructor approach have the same public api (whether the method is called clone() or deepCopy() doesn't matter much), so which approach you use is an implementation detail. The copy-constructor approach is more verbose as you provide both a constructor and a method calling that constructor, but it can be more easily generalized to a general type conversion facility, allowing things like:

public Teacher(Person p) {
    ...
    say("Yay, I got a job");
}

建议:如果只需要相同的副本,请使用clone,使用copy-constructors如果您的呼叫者可能希望请求特定类型的实例。

Recommendation: Use clone if you only want an identical copy, use copy-constructors if your caller might wish to request an instance of a specific type.

这篇关于使用复制构造函数而不是Object.clone进行深层复制的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆