java 深拷贝和浅拷贝
JAVA深拷贝和浅拷贝
参考博客:https://www.jianshu.com/p/94dbef2de298
浅拷贝(shallow Copy)
1.什么是浅拷贝
浅拷贝首先会创建一个新的对象,这个对象和原始对象属性值相同。如果原始对象是数值类型对象,那么拷贝的就是基本类型的值;如果拷贝的对象是引用类型的话,拷贝的就是原始对象的地址,可以说浅拷贝就相当于是一个指针指向被拷贝对象的地址。
2.浅拷贝特点
①对于基础类型的成员对象,浅拷贝会以值传递的方式,直接将属性值赋值给新的对象。修改原始对象的成员或者修改新对象的成员,不会另外一方的值。
②对于引用类型,比如数组或者类对象,因为引用类型是引用传递,所以浅拷贝只是把内存地址赋值给了成员变量,它们指向了同一内存空间。改变其中一个,会对另外一个也产生影响。
3.实现浅拷贝
public class Subject {
private String name;
public Subject(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Subject{" +
"name='" + name + '\'' +
'}';
}
}
实现浅拷贝对象的类,要实现Cloneable接口
public class Student implements Cloneable {
private String name;
//引用类型
private Subject subject;
private double score;
public Student(String name, Subject subject, double score) {
this.name = name;
this.subject = subject;
this.score = score;
}
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;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
protected Object clone() throws CloneNotSupportedException {
//默认调用父类方法
return super.clone();
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", subject=" + subject +
", score=" + score +
'}';
}
}
测试类
public class ShallowCopy {
public static void main(String[] args) throws CloneNotSupportedException {
Subject sub1 = new Subject("math");
Student stuA = new Student("a", sub1, 77.5);
Student stuB = (Student) stuA.clone();//拷贝对象
stuB.setName("b");
stuB.setScore(88.5);
stuB.getSubject().setName("science");
System.out.println(stuA);
System.out.println(stuB);
}
}
运行结果
Student{name='a', subject=Subject{name='science'}, score=77.5}
Student{name='b', subject=Subject{name='science'}, score=88.5}
可以看出对新复制出对象的基本数据类型成员进行修改,并不会改变原有对象中的成员,但是对引用类型成员进行修改,则原始对象中的成员也会被改变。
浅拷贝结构图大致如下:
4.关于对象赋值
现在将
Student stuB = (Student) stuA.clone();
修改为
Student stuB = stuA;
可以看到结果
Student{name='b', subject=Subject{name='science'}, score=88.5}
Student{name='b', subject=Subject{name='science'}, score=88.5}
可以看出,对象赋值仅仅是将引用赋值给了新的对象,这两个对象指向同一的内存地址,修改其中一个对象的成员,另一个也会随之修改。
深拷贝(deep Copy)
1.什么是深拷贝
浅拷贝拷贝的对象中的引用类型指向的是同一块堆内存地址。这会使我们修改拷贝对象内容时会有数据安全隐患。深拷贝,在拷贝引用类型成员变量时,为引用类型的数据成员另辟了一个独立的内存空间,实现真正内容上的拷贝。
2.深拷贝特点
①对于引用类型,深拷贝都会新建一个对象空间来存储这些拷贝的引用,这样就会使它们指向不同的内存地址改变其中一个,不会影响另外一个。
②对于有多层对象的,每个对象都需要实现 Cloneable
并重写 clone()
方法,进而实现了对象的串行层层拷贝
③由于得为每一个引用类型成员开辟新的空间,相比较于浅拷贝,深拷贝将会更加消耗内存空间,并且花费更多时间。
3.实现深拷贝
修改subject来,使其也实现Cloneable
并重写 clone()
public class Subject implements Cloneable{
private String name;
public Subject(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Subject{" +
"name='" + name + '\'' +
'}';
}
}
重写student的clone方法,拷贝引用成员subject
public class Student implements Cloneable {
private String name;
//引用类型
private Subject subject;
private double score;
public Student(String name, Subject subject, double score) {
this.name = name;
this.subject = subject;
this.score = score;
}
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;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
protected Object clone() throws CloneNotSupportedException {
//默认调用父类方法
Student student = (Student) super.clone();
student.subject = (Subject) subject.clone();
return student;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", subject=" + subject +
", score=" + score +
'}';
}
}
测试类
public class DeepCopy {
public static void main(String[] args) throws CloneNotSupportedException {
Subject sub = new Subject("地理");
Student stuA = new Student("张三", sub, 75.5);
Student stuB = (Student) stuA.clone();
stuB.setName("李四");
stuB.setScore(66.5);
stuB.getSubject().setName("化学");
System.out.println(stuA);
System.out.println(stuB);
}
}
测试结果
Student{name='张三', subject=Subject{name='地理'}, score=75.5}
Student{name='李四', subject=Subject{name='化学'}, score=66.5}
可以看出,深拷贝后,不管是基础数据类型还是引用类型的成员变量,修改后都不会影响原始对象
深拷贝的结构图大致如下: