深入理解Java淺拷貝和深拷貝
阿新 • • 發佈:2022-03-16
首先說一下什麼是引用拷貝和物件拷貝。
1. 引用拷貝:
引用拷貝就是建立一個指向物件的引用變數的拷貝,拷貝後生成的物件和原來的物件仍是一個物件,也就是說他們在記憶體空間中的地址是一樣的。
2. 物件拷貝
物件拷貝就是建立物件本身的一個副本,就是在記憶體空間中開闢一個新的區域存放該物件,這時候就是兩個物件了!
深拷貝和淺拷貝都是物件拷貝
1.淺拷貝
被複制物件的所有變數都含有與原來的物件相同的值,而所有的對其他物件的引用仍然指向原來的物件。即物件的淺拷貝會對“主”物件進行拷貝,但不會複製主物件裡面的物件。”裡面的物件“會在原來的物件和它的副本之間共享。
簡單來說就是隻拷貝你考慮的物件,對於內部物件和原來的物件共享。
下面結合程式碼來看看:
//教師類,是學生類的內部物件 //實現Cloneable介面,預設實現的是淺拷貝 public class Teacher implements Cloneable { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
//學生類,也是我們要拷貝的“主類” public class Student implements Cloneable { private String name; private int age; private Teacher teacher; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
測試類:
public class shallowCopy {
public static void main(String[] args) throws CloneNotSupportedException {
Teacher teacher = new Teacher();
teacher.setName("liumei");
teacher.setAge(25);
Student student1 = new Student();
student1.setName("mike");
student1.setAge(18);
student1.setTeacher(teacher);
Student student2 = (Student) student1.clone();
//student
System.out.println(student1);
System.out.println(student2);
//teacher
System.out.println(student1.getTeacher());
System.out.println(student2.getTeacher());
}
}
測試結果:
從結果中可以看出,student1和student2是兩個物件,而兩個學生物件的teacher物件地址卻是相同的,這也就印證了我們上邊的結論,淺拷貝是不拷貝內部引用的物件的!
2. 深拷貝
深拷貝是一個整個獨立的物件拷貝,深拷貝會拷貝所有的屬性,並拷貝屬性指向的動態分配的記憶體。當物件和它所引用的物件一起拷貝時即發生深拷貝。深拷貝相比於淺拷貝速度較慢並且花銷較大。
簡而言之,深拷貝把要複製的物件和引用的物件都複製了一遍。
下面結合程式碼來看看:
教師類和上述程式碼一致,我們只看學生類。
public class Student implements Cloneable {
private String name;
private int age;
private Teacher teacher;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
/**
* 深拷貝:不僅賦值主物件,還將內部的物件也重新複製一份
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
//拷貝student物件
Student student = (Student) super.clone();
//拷貝teacher物件,並將其放入拷貝後生成的student物件中
student.setTeacher((Teacher) teacher.clone());
return student;
}
}
測試類與淺拷貝一致,我們直接看結果:
誒? 這次不僅兩個學生類的地址不一樣了,連內部的teacher類物件的地址也不相同了!
也就是說 深拷貝確實是將內部的引用物件也重新為它開闢空間!
下面看看淺拷貝和深拷貝在記憶體空間中的圖解應該就更能理解了。