前言
??今天在對ArrayList進行復制的時候,發現復制后的List中的對象的屬性發生改變后,原數組也會發生改變,經過一番檢索后總結出一些結論。
??在日常開發中,對象的復制是非常常見的,而實際上,復制類型也是有區分的,主要有深復制和淺復制。
淺復制
??對基本數據類型進行值傳遞,對引用數據類型進行引用傳遞般的拷貝.如圖為淺拷貝的核心:
實現方式
通過java中的clone方法
??通過clone方式實現淺復制需要,它的實現必須實現 Cloneable
接口,否者將拋出 CloneNotSupportedException
這個異常。
??先給定兩個實體類
public class Student1 implements Cloneable{
Age age;
String name;
public Age getAge() {
return age;
}
public void setAge(Age age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Student1{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
public class Age {
int num;
public Age(int num) {
this.num = num;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
@Override
public String toString() {
return "Age{" +
"num=" + num +
'}';
}
}
??再看測試方法:
public class Test {
public static void main(String ...args) throws CloneNotSupportedException {
Student1 student1 = new Student1();
Age age = new Age(21);
student1.setAge(age);
student1.setName("小明");
//1.通過clone()克隆
Student1 student2 = (Student1) student1.clone();
System.out.println(student1);
System.out.println(student2);
//2.修改student1
student1.getAge().setNum(22);
System.out.println(student1);
System.out.println(student2);
//3.查看hash
System.out.println(student1.getAge().hashCode());
System.out.println(student2.getAge().hashCode());
}
}
??結果如圖:
結果
從結果可以看到,第一步通過調用clone()方法后,創建一個和student1一樣的新對象,但這只是淺拷貝,這從第二步就可以看出,當改變student1的屬性時,student2也根本改變,而且通過hash值也能看出對象屬性的hash是一致的。
通過構造函數實現復制
先給定一個實體類
public class Student2 {
Age age;
String name;
public Student2(Age age, String name) {
this.age = age;
this.name = name;
}
Student2(Student2 p2){
this.age = p2.age;
this.name = p2.name;
}
public Age getAge() {
return age;
}
public void setAge(Age age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student1{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
public class Age {
int num;
public Age(int num) {
this.num = num;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
@Override
public String toString() {
return "Age{" +
"num=" + num +
'}';
}
}
再給定測試類
public static void main(String ...args) {
Age age = new Age(21);
Student2 student1 = new Student2(age,"小明");
//構造函數
Student2 student2 = new Student2(student1);
System.out.println(student1);
System.out.println(student2);
//修改student1
student1.getAge().setNum(22);
System.out.println(student1);
System.out.println(student2);
//查看對象屬性的hash
System.out.println(student1.getAge().hashCode());
System.out.println(student2.getAge().hashCode());
}
結果如圖:
結果
同樣可以看到與clone對象一樣的結果。
深復制
深復制一樣有兩種方式實現:
- 序列化(serialization)這個對象,再反序列化回來,就可以得到這個新的對象,無非就是序列化的規則需要我們自己來寫。
- 繼續利用 clone() 方法,既然 clone() 方法,是我們來重寫的,實際上我們可以對其內的引用類型的變量,再進行一次 clone()。
繼續改寫Age類,讓其實現Cloneable接口,同時改寫Student1的clone方法。
public class Age implements Cloneable{
String name;
int num;
public Age(int num) {
this.num = num;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
@Override
public String toString() {
return "Age{" +
"num=" + num +
'}';
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Student1 implements Cloneable{
Age age;
String name;
public Age getAge() {
return age;
}
public void setAge(Age age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public Object clone() throws CloneNotSupportedException {
Student1 clone = (Student1) super.clone();
clone.age = (Age) this.age.clone();
return clone;
}
@Override
public String toString() {
return "Student1{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
測試方法:
public class Test {
public static void main(String ...args) throws CloneNotSupportedException {
Student1 student1 = new Student1();
Age age = new Age(21);
student1.setAge(age);
student1.setName("小明");
//1.通過clone()克隆
Student1 student2 = (Student1) student1.clone();
System.out.println(student1);
System.out.println(student2);
//2.修改student1
student1.getAge().setNum(22);
System.out.println(student1);
System.out.println(student2);
//3.查看hash
System.out.println(student1.getAge().hashCode());
System.out.println(student2.getAge().hashCode());
}
}
結果:
1536157402781.png
可以看到,這次在改變student1的時候,student2不會跟著改變。hash值也不一樣了。