Java 中的 clone() 方法是一种创建对象副本的方式,它是 Cloneable 接口的一部分,其作用是复制原始对象的内容并创建一个新的对象。
一、clone() 方法的语法与用法
clone() 方法的语法如下:
public Object clone() throws CloneNotSupportedException
clone() 方法可以复制任何一个实现了 Cloneable 接口的对象,但是如果这个对象没有实现 Cloneable 接口,那么将会抛出 CloneNotSupportedException 异常。在使用 clone() 方法时,需要注意以下几点:
-
实现 Cloneable 接口:为了让一个类的实例能被 clone() 复制,必须实现 Cloneable 接口,并重写它的 clone() 方法。
-
重写 clone() 方法:因为 Object 类的 clone() 方法是 protected 访问级别的,所以需要重写 clone() 方法以改变其访问级别为 public,并声明为抛出 CloneNotSupportedException 异常。
-
原对象与克隆对象不同:clone() 方法复制出来的新对象和原对象不是同一个对象。如果原对象发生变化,不会影响到新的克隆对象。同时,克隆对象和原对象所在的类类型相同,但是对象引用都是独立的,对克隆后的对象进行更改不会对原始对象产生影响。
下面是一个最简单的示例,将 Car 类实现 clone() 方法:
public class Car implements Cloneable {
private String name;
private int num;
public Car(String name, int num) {
this.name = name;
this.num = num;
}
// 重写 cloning 方法
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public void setName(String name) {
this.name = name;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public int getNum() {
return num;
}
}
在这个代码里,我们不仅实现了 Cloneable 接口,还重写了 clone() 方法,并使用了 super.clone() 方法来获得一个新的复制对象。
二、示例说明
示例一:复制数组
接下来,为了更好地说明 clone() 方法,我们使用一个包含多个 Car 对象的数组作为案例。 我们可以创建一个数组 cars,并将实例存储在 cars 数组中:
public class CloneApplication {
public static void main(String[] args) {
Car[] cars = {new Car("Bob", 25), new Car("Tom", 22)};
// 使用 clone() 方法复制数组
Car[] cloneCars = cars.clone();
// 比较两个数组是否相等
System.out.println(cars == cloneCars); // false
System.out.println(cars[0] == cloneCars[0]); // true
System.out.println(cars[1] == cloneCars[1]); // true
// 修改复制的对象。
cloneCars[0].setName("Jack");
cloneCars[0].setNum(20);
// 只是因为车的容器有所不同,所以它们不相等。
System.out.println(cars[0].getNmae()); // Bob
System.out.println(cloneCars[0].getNmae()); // Jack
}
}
在这个示例里,我们定义了一个数组 cars,然后使用 clone() 方法复制 cars,最后修改 cloneCars 中的一个对象,从输出结果来看,两个数组不相等,并且 cloneCars 的第一个元素经过修改,原始数组 cars 的第一个元素不受影响。
示例二:实现深度复制
现在,让我们创建一个包含复杂对象图的类,来演示如何将对象图复制到新对象中。 假设我们要将一个带有内部类的 Student 对象进行复制,Student 类通常看起来会像这样:
public class Student implements Cloneable {
private String name;
private int age;
private Books books;
public Student(String name, int age, Books books) {
this.name = name;
this.age = age;
this.books = books;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Student cloned = (Student) super.clone();
cloned.setBooks((Books) cloned.getBooks().clone());
return cloned;
}
// 将getter,setter省略
}
在这个示例里,我们使用另一个类 Books 来存储一系列书籍,这个类也实现了 clone() 方法。 在 Student 类中,我们先调用 super.clone() 复制基本属性,然后将类的引用类型复制到新的对象中。 在这种情况下,我们需要保证 books 引用类型而不是修改原始对象。
现在,我们就可以使用这个类创建对象,并将其复制到一个新对象中:
public class CloneApplication {
public static void main(String[] args) throws CloneNotSupportedException {
Student student = new Student("Tom", 17, new Books());
Student clonedStudent = (Student) student.clone();
System.out.println(student.getName()); // Tom
System.out.println(clonedStudent.getName()); // Tom
// 修改克隆的对象
clonedStudent.setName("Alice");
clonedStudent.getBooks().setName("English");
// 只有克隆的对象改变了
System.out.println(student.getName()); // Tom
System.out.println(clonedStudent.getName()); // Alice
System.out.println(student.getBooks().getName()); // null
System.out.println(clonedStudent.getBooks().getName()); // English
}
}
可以看到,我们成功地创建了一个新的对象,并且修改了其中的一个成员变量,然而原始对象并没有发生任何变化。
结语
有了 clone() 方法,您可以轻松地复制对象,并且新的复制对象具有原始对象的所有属性。 我们需要注意的是,被 clone() 方法复制出来的对象和原对象是两个不同的对象,对其中一个对象做出的改变并不会影响另一个对象。