java – 使用复制构造函数而不是Object.clone进行深度复制的正确方法

我有一些代码使用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());
         }
     }
 }

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

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中克隆的邪恶的讨论,克隆替代方案需要更少的代码和更少的强制转换(至少在这种情况下).

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

解决方法

代替:
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 ...");
    }
}

所以调用者不必处理永远不会发生的异常,也不必进行强制转换.

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

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

现在,编译器可以检查您是否为所有子类型提供了深层副本,并且您不需要任何强制转换.

最后,请注意,克隆和复制构造方法都具有相同的公共API(无论方法名为clone()还是deepcopy()都无关紧要),因此您使用的方法是实现细节.复制构造方法更加冗长,因为您提供了构造函数调用该构造函数方法,但它可以更容易地推广到通用类型转换工具,允许以下内容

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


应用场景 C端用户提交工单、工单创建完成之后、会发布一条工单创建完成的消息事件(异步消息)、MQ消费者收到消息之后、会通知各处理器处理该消息、各处理器处理完后都会发布一条将该工单写入搜索引擎的消息、最终该工单出现在搜索引擎、被工单处理人检索和处理。 事故异常体现 1、异常体现 从工单的流转记录发现、
线程类,设置有一个公共资源 package cn.org.chris.concurrent; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Descrip
Java中的数字(带有0前缀和字符串)
在Java 9中使用JLink的目的是什么?
Java Stream API Filter(过滤器)
在Java中找到正数和负数数组元素的数量
Java 9中JShell中的不同启动脚本是什么?
使用Java的位填充错误检测技术
java中string是什么
如何使用Java中的JSON-lib API将Map转换为JSON对象?
Java菜单驱动程序以检查数字类型
使用Junit的Maven项目 - 检查银行账号
JAVA编程基础
在Java中使用throw、catch和instanceof来处理异常
在Java中,将数组分割为基于给定查询的子数组后,找到子数组的最大子数组和
如何在Java中从给定的字符串中删除HTML标签?
在PHP中,IntlChar getBlockCode()函数的翻译如下:
如何在Android中实现按下返回键再次退出的功能?
如何使用Java中的流式API解析JSON字符串?
Java中的模式类