Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 "拷贝". 但是要想合法调用 clone 方法, 必须要
先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常.
情况一:对自定义类型进行拷贝
class Student implements Cloneable{
public String name;
public int age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
protected Object clone() throws CloneNotSupportedException {
// return super.clone();
// super.clone只是克隆了一个学生对象,向下转型为Student
Student student = (Student) super.clone();
return student;
}
}
public class test {
public static void main1(String[] args) throws CloneNotSupportedException{
Student student1 = new Student();
// 返回的是Object类型,需要向下转型之后才能被接收
Student student2 = (Student) student1.clone();
System.out.println(student1);
System.out.println(student2);
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/12ef035b5e83d4c8360e24c03045f189.png)
运行结果 这就可以对自定义类型进行拷贝了。
![](https://i-blog.csdnimg.cn/blog_migrate/f07696692d021a135f9ab1094cf8f1eb.png)
Student student2 = (Student) student1.clone(); 向下转型,由object类转换成为student类型, 克隆一个student1对象的一个副本。
情况二:当使用组合的思想在student类中加入一个实例化的类,如何实现拷贝呢?
class Student implements Cloneable{
public String name;
public int age;
// 组合的使用
public Money m = new Money();
public Hair H = new Hair();
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
protected Object clone() throws CloneNotSupportedException {
Student student = (Student) super.clone();
return student
}
}
class Money implements Cloneable{
public double money = 12.25;
}
public class test {
public static void main1(String[] args) throws CloneNotSupportedException{
Student student1 = new Student();
// 完成对象的深拷贝
// 返回的是Object类型,需要向下转型之后才能被接收
Student student2 = (Student) student1.clone();
System.out.println(student1.m.money);
System.out.println(student2.m.money);
student2.m.money = 99.0;
System.out.println(student1.m.money);
System.out.println(student2.m.money);
}
}
以上代码就完成了拷贝,那么思考一下这是深拷贝还是浅拷贝呢?
运行结果如下:当利用student2引用进行修改money的值的时候,打印student1引用指向对象的内容也发生了改变,这就是浅拷贝。以上代码只是拷贝了student1这个对象,而这个对象里面的Money对象没有拷贝。
![](https://i-blog.csdnimg.cn/blog_migrate/a221106a8849c66fc57de0b5a71b874f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/100ed951b5cdbae882f422184d82cb41.png)
具体只是复制了指向money的地址。而没有进行克隆money的值。
我们现在要做的是克隆money的值。
![](https://i-blog.csdnimg.cn/blog_migrate/d4e3d6f06bc7e1ea4a2c9a40db70cb32.png)
上图才是真正的拷贝。
此时我们将Cloneable接口在Money类进行实现,同时重写clone方法。利用student引用进行拷贝Money对象。
代码如下所示:
class Student implements Cloneable{
public String name;
public int age;
// 组合的使用
public Money m = new Money();
public Hair H = new Hair();
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
protected Object clone() throws CloneNotSupportedException {
// 重写object的方法,实现深拷贝
// return super.clone();
// super.clone只是克隆了一个学生对象,向下转型为Student
Student student = (Student) super.clone();
// 利用Student访问成员,m,将Money对象进行拷贝
student.m = (Money) this.m.clone();
return student;
}
}
public class test {
public static void main1(String[] args) throws CloneNotSupportedException{
Student student1 = new Student();
// 完成对象的深拷贝
// 返回的是Object类型,需要向下转型之后才能被接收
Student student2 = (Student) student1.clone();
System.out.println(student1.m.money);
System.out.println(student2.m.money);
student2.m.money = 99.0;
System.out.println(student1.m.money);
System.out.println(student2.m.money);
}
}
class Money implements Cloneable{
public double money = 12.25;
// 声明Money是有Cloneable接口的
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
重点代码是下图,在Student类中重写clone方法时,实现利用student引用进行拷贝Money对象,从而达到深拷贝。
![](https://i-blog.csdnimg.cn/blog_migrate/2fd413043a2e6c39f828956cbaf13326.png)
这样才将student1完成了深拷贝。