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编程,这也证明了这是一种深拷贝。