关于deepClone

时间:2011-09-14 04:51:51

标签: java

当我运行下面的代码时,为什么会抛出此错误?

Exception in thread "main" java.lang.CloneNotSupportedException: Student
    at java.lang.Object.clone(Native Method)
    at Student.clone(Student.java:44)
    at StudentApp.main(StudentApp.java:10)

这是我的主要课程:

public static void main(String[] args) throws CloneNotSupportedException {

    Address address = new Address("湖南省长沙市林科大","1234567",20);
    Student stu = new Student("诸葛亮量",20);
    stu.setAddress(address);

    Student stu2 = (Student)stu.clone();
    stu2.setAddress(new Address("湖南省常德市区","484848348",22));

    stu2.setName("张飞飞");
    stu2.setAge(23);
    stu.sayHi();
    stu2.sayHi();
}

这是学生班:

public class Student{

    private String name;
    private int age;
    private Address address;

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public Student() {
        super();
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public void sayHi() {
        System.out.println("大家好,我是" + this.getName() + "同学,我今年" + this.getAge()
                + "岁了……我的HashCode是:" + this.hashCode()+"。我家庭住址是"+address.getAddress()+",家庭住址的HashCode为:"+address.hashCode());
    }

}

这是地址类:

public class Address {

    private String address;
    private String tel;
    private int roadNum;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getTel() {
        return tel;
    }

    public void setTel(String tel) {
        this.tel = tel;
    }

    public int getRoadNum() {
        return roadNum;
    }

    public void setRoadNum(int roadNum) {
        this.roadNum = roadNum;
    }

    public Address() {
        super();
    }

    public Address(String address, String tel, int roadNum) {
        super();
        this.address = address;
        this.tel = tel;
        this.roadNum = roadNum;
    }

}

4 个答案:

答案 0 :(得分:4)

来自javadoc

  

在未实现的实例上调用Object的clone方法   Cloneable接口导致异常   抛出CloneNotSupportedException。

您是否尝试让Student类实现Cloneable接口?

答案 1 :(得分:2)

不要尝试使用clone(),而是编写一个复制构造函数,该构造函数接受学生的实例并单独复制它的字段。然后您不必担心clone的语义。在您的示例中,这意味着在Address上也有一个复制构造函数,因为学生有一个Address字段。

阅读Joshua Bloch的Effective Java,了解应该避免克隆的原因。

public class Student {

    final private String name;
    final private int age;
    final private Address address;

    public Address getAddress() {
        return address;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public Student(Student copyStudent) {
        this.name = new String(copyStudent.getName());
        this.age = copyStudent.getAge();
        this.address = new Address(copyStudent.getAddress());
    }
}

来自Effective Java

  

复制构造函数方法及其静态工厂变体有很多   克隆/克隆的优势:它们不依赖于风险   语外对象创造机制;他们不要求   无法执行的遵守不良记录的公约;他们不   与正确使用最终字段相冲突;他们不需要   客户端捕获不必要的已检查异常;他们提供了一个   静态类型的对象到客户端。虽然不可能放一个   在接口中复制构造函数或静态工厂,Cloneable失败   作为一个接口,因为它缺少一个公共克隆方法。   因此,您不会通过使用副本放弃接口功能   构造函数而不是克隆方法。此外,还有一个复制构造函数   (或静态工厂)可以采用其类型适当的参数   该类实现的接口。例如,所有通用目的   按照惯例,集合实现提供了一个复制构造函数   其参数的类型为Collection或Map。基于接口的副本   构造函数允许客户端选择执行   复制,而不是强迫客户端接受执行   原本的。例如,假设你有一个LinkedList l和你   想要将其复制为ArrayList。克隆方法不提供此功能   功能,但使用复制构造函数很容易:new   ArrayList的(1)。鉴于与Cloneable相关的所有问题,它   可以肯定地说,其他接口不应该扩展它   为继承而设计的类(第15项)不应该实现它。   由于它的许多缺点,一些专家程序员只是简单   选择永远不要覆盖克隆方法,永远不要调用它   除了,或许,便宜地复制数组。请注意,如果你不这样做   至少在类上提供一个行为良好的受保护克隆方法   为继承而设计,子类是不可能的   实现Cloneable。

答案 2 :(得分:1)

学生需要实施Cloneable。

答案 3 :(得分:0)

如果您不想在源和目标学生实例中共享地址实例,则学生和地址都需要“深度”克隆:

class Student implements Cloneable {
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student result = (Student)super.clone();
        result.setAddress((Address)getAddress().clone());
        return result;       
    }
...
}

class Address implements Cloneable{
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return  (Address) super.clone();
    }
...
}