详解Java的clone()方法:返回对象的副本

  • Post category:Java

Java中的clone()方法是一种对象复制的方法,可以用来复制一个对象。该方法在Object类中被定义为一个protected方法,因此在使用时必须进行重写并在子类中进行实现,同时实现Cloneable接口。

下面通过以下步骤来详细讲解Java的clone()方法:

1.重写clone()方法

首先,在我们想要复制一个对象时,必须在该类中重写clone()方法。此时需要保证该类实现了Cloneable接口,这个接口没有定义任何的方法,只是起到一个标识作用,表示这个类可以被复制。

示例代码如下:

public class Person implements Cloneable {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // 重写clone方法
    public Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }
    // 省略getters and setters
}

2.实现Cloneable接口

其次,创建一个实现Cloneable接口的类,实现该类的复制方法,返回一个该类的副本对象。

示例代码如下:

class Person implements Cloneable
{
    private String name;
    private int age;

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

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

这里需要注意:虽然我们现在在Person类中重写了clone方法,但是在使用时,如果不实现Cloneable接口,则在进行复制时,会抛出CloneNotSupportedException。

3.浅拷贝与深拷贝的区别

Java中的clone()方法有两种拷贝方式,即浅拷贝和深拷贝。

浅拷贝只是复制了一个对象,但是对象中引用的其他对象只是复制了指向这些对象的引用。这就导致,如果我们改变了其中一个对象,那么另一个对象也会被改变。

而深拷贝是对整个对象以及对象所引用的其他对象进行了复制,并创建了一个新的对象。这样两个对象之间就没有了关系。

下面分别使用浅拷贝和深拷贝两种方式来实现对象的复制。

4.浅拷贝的示例

浅拷贝示例代码如下:

class Course implements Cloneable {
    private String name;
    public Course(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Student implements Cloneable {
    private String name;
    private int age;
    private Course course;
    public Student(String name,int age,Course course) {
        this.name = name;
        this.age = age;
        this.course = course;
    }
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
    public void setCourse(String name) {
        course.setName(name);
    }
    public String toString() {
        return "Student: " + name + ", " + age + ", Course: " + course.getName();
    }
}

public class CloneTest {
    public static void main(String[] args) {
        Course course = new Course("Java编程");
        Student student1 = new Student("张三", 20, course);
        Student student2 = (Student) student1.clone();
        System.out.println("修改前:");
        System.out.println(student1.toString());
        System.out.println(student2.toString());
        student2.setCourse("C++编程");
        System.out.println("修改后:");
        System.out.println(student1.toString());
        System.out.println(student2.toString());
    }
}

这里我们创建了一个学生类,用来保存学生的姓名、年龄以及选修的课程。在进行对象复制时,我们通过重写clone()方法来复制对象,并且在学生类中定义了一个修改选修课程名称的方法。

然后,我们创建了一个Java编程的课程对象,然后创建了一个张三同学并选修了这个课程。接着,我们通过浅拷贝的方式复制了这个张三。在修改选修的课程名称后,我们发现张三的选修课程也发生了变化。这是因为浅拷贝只是复制了一个引用指向同一个课程对象。

5.深拷贝的示例

深拷贝示例代码如下:

class Course implements Cloneable {
    private String name;
    public Course(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Student implements Cloneable {
    private String name;
    private int age;
    private Course course;
    public Student(String name,int age,Course course) {
        this.name = name;
        this.age = age;
        this.course = course;
    }
    public Object clone() {
        try {
            Student s = (Student) super.clone();
            s.course = (Course) course.clone();
            return s;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
    public void setCourse(String name) {
        course.setName(name);
    }
    public String toString() {
        return "Student: " + name + ", " + age + ", Course: " + course.getName();
    }
}

public class CloneTest {
    public static void main(String[] args) {
        Course course = new Course("Java编程");
        Student student1 = new Student("张三", 20, course);
        Student student2 = (Student) student1.clone();
        System.out.println("修改前:");
        System.out.println(student1.toString());
        System.out.println(student2.toString());
        student2.setCourse("C++编程");
        System.out.println("修改后:");
        System.out.println(student1.toString());
        System.out.println(student2.toString());
    }
}

在该示例中,我们实现了深拷贝。我们同样创建了一个学生类和课程类。但是在进行深拷贝时,我们重写了clone()方法,在复制学生对象时,我们同时复制了该学生选修课程的对象,并且在实现这个课程对象的clone()方法时,我们同样进行了复制,以保证两个课程对象之间没有关系。

在运行该示例后,我们发现即使我们在修改选修的课程名称后,张三所选修的课程名称依然是Java编程,这也证明了这是一种深拷贝。