简述
我们在Java开发时,有时会涉及到对象拷贝复制,就是将一个对象的所有属性(成员变量)复制到另一个对象中,而拷贝又分为浅拷贝和深拷贝,造成这种分法的主要原因就是【值传递】和【引用传递】的不同
【浅拷贝】
- 若成员变量为基本数据类型,拷贝时为【值传递】,是两份不同的数据,改变A类中的该变量,B类不会变化
- 若成员变量为引用类型,拷贝时为【引用传递】,拷贝的是引用变量,实际上两个引用变量指向的是一个实例对象,若改变A类中的该变量,B会变化,即为【浅拷贝】
【深拷贝】
- 深拷贝就是对引用类型的成员变量拷贝时,拷贝整个对象,而不是只拷贝引用
clone()方法
- Object提供了clone()方法帮助我们进行拷贝,但它只是浅拷贝,如果需要深拷贝,需要重写clone()方法的逻辑
- 由源码protected native Object clone() throws CloneNotSupportedException可知,我们无法直接调用clone()方法,我们需要重写该方法并使用super.clone()方法去调用Object的clone方法来实现
- 使用clone方法的类必须实现Cloneable接口,否则会抛出异常CloneNotSupportedException
【上代码!!!】
【浅拷贝】
public class Teacher {
private String name;
private Subject subject;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Subject getSubject() {
return subject;
}
public void setSubject(Subject subject) {
this.subject = subject;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Teacher [name=" + name + ", subject=" + subject + "]";
}
}
public class Subject {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Subject [name=" + name + "]";
}
}
public static void main(String[] args) {
Subject subject = new Subject();
subject.setName("数学");
Teacher teacher1 = new Teacher();
teacher1.setName("张老师");
teacher1.setSubject(subject);
Teacher teacher2 = null;
try {
System.out.println("克隆后------------------");
teacher2 = (Teacher) teacher1.clone();
System.out.println("teacher 2:" + teacher2);
System.out.println("改变teacher1后------------------");
teacher1.getSubject().setName("语文");
System.out.println("teacher 2:" + teacher2);
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
可以发现改变teacher1的subject后,克隆的对象teacher2的subject也发生了变化,这就是【浅拷贝】
【深拷贝】
public class Teacher implements Cloneable {
private String name;
private Subject subject;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Subject getSubject() {
return subject;
}
public void setSubject(Subject subject) {
this.subject = subject;
}
@Override
public Object clone() throws CloneNotSupportedException {
Teacher teacher = (Teacher) super.clone();
Subject subject = (Subject) teacher.getSubject().clone();
teacher.setSubject(subject);
return teacher;
}
@Override
public String toString() {
return "Teacher [name=" + name + ", subject=" + subject + "]";
}
}
public class Subject implements Cloneable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Subject [name=" + name + "]";
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public static void main(String[] args) {
Subject subject = new Subject();
subject.setName("数学");
Teacher teacher1 = new Teacher();
teacher1.setName("张老师");
teacher1.setSubject(subject);
Teacher teacher2 = null;
try {
System.out.println("克隆后------------------");
teacher2 = (Teacher) teacher1.clone();
System.out.println("teacher 2:" + teacher2);
System.out.println("改变teacher1后------------------");
teacher1.getSubject().setName("语文");
System.out.println("teacher 2:" + teacher2);
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
其实就是让subject也实现克隆,然后在teacher的clone方法里,重新setSubject为subject的克隆,就完成了深拷贝
网友评论