1. 概述
Java对象要调用 clone 进行复制,必须实现 Cloneable 接口,否则会抛出
CloneNotSupportedException
的异常。
clone 方法默认是浅复制,如果要实现深复制,那必须在clone方法调用对象成员的复制方法。
- 浅复制:复制对象时,对象内部引用类型的成员,仍然共用内存空间。此时A对象修改这个成员的属性,B对象的该成员也会受影响。
- 深复制:复制对象时,对象内部引用类型的成员,也会重新开辟新的空间。此时A对象和B对象完全互不干扰。
2. 浅复制clone
Grade: 班级类,实现了Cloneable接口
@Data
public class Grade implements Cloneable{
//名称
private String name;
//班主任
private Teacher headTeacher;
@Override
public Object clone() throws CloneNotSupportedException {
Grade grade = (Grade) super.clone();
return grade;
}
}
Teacher: 教师类,同样实现Cloneable接口
@Data
public class Teacher implements Cloneable{
//姓名
private String name;
@Override
public Object clone() throws CloneNotSupportedException {
Teacher teacher = (Teacher) super.clone();
return teacher;
}
}
- 创建教师对象teacher,班级对象grade1
- 从grade1复制出班级对象grade2
- 修改grade1的名称
- 修改grade1的班主任的姓名
public static void main(String[] args) throws CloneNotSupportedException {
Teacher teacher = new Teacher();
teacher.setName("张三");
Grade grade1 = new Grade();
grade1.setName("一班");
grade1.setHeadTeacher(teacher);
Grade grade2 = (Grade) grade1.clone();
grade1.setName("小一班");
grade1.getHeadTeacher().setName("李四");
System.out.println(grade1);
System.out.println(grade2);
}
看下执行结果
Grade(name=小一班, headTeacher=Teacher(name=李四))
Grade(name=一班, headTeacher=Teacher(name=李四))
- 班级name的修改是互不影响的。上面说了,浅复制是引用类型才公共内存空间,String是特殊的引用类型。
- 修改grade1的班主任name,直接影响了grade2的班主任,因为headTeacher就是一个引用类型变量。
3. 深复制clone
修改上面Grade类的clone代码,复制的时候把Teacher对象也复制一份,这就是深复制。
@Override
public Object clone() throws CloneNotSupportedException {
Grade grade = (Grade) super.clone();
grade.setHeadTeacher((Teacher)this.headTeacher.clone());
return grade;
}
其他代码不变,然后重新运行程序,输出如下:
Grade(name=小一班, headTeacher=Teacher(name=李四))
Grade(name=一班, headTeacher=Teacher(name=张三))
可以看到,headTeacher怎么修改都互不影响,深复制成功。