前言
??今天在對(duì)ArrayList進(jìn)行復(fù)制的時(shí)候,發(fā)現(xiàn)復(fù)制后的List中的對(duì)象的屬性發(fā)生改變后,原數(shù)組也會(huì)發(fā)生改變甲献,經(jīng)過(guò)一番檢索后總結(jié)出一些結(jié)論。
??在日常開(kāi)發(fā)中谦秧,對(duì)象的復(fù)制是非常常見(jiàn)的竟纳,而實(shí)際上,復(fù)制類(lèi)型也是有區(qū)分的疚鲤,主要有深復(fù)制和淺復(fù)制锥累。
淺復(fù)制
??對(duì)基本數(shù)據(jù)類(lèi)型進(jìn)行值傳遞,對(duì)引用數(shù)據(jù)類(lèi)型進(jìn)行引用傳遞般的拷貝.如圖為淺拷貝的核心:
實(shí)現(xiàn)方式
通過(guò)java中的clone方法
??通過(guò)clone方式實(shí)現(xiàn)淺復(fù)制需要集歇,它的實(shí)現(xiàn)必須實(shí)現(xiàn) Cloneable
接口桶略,否者將拋出 CloneNotSupportedException
這個(gè)異常。
??先給定兩個(gè)實(shí)體類(lèi)
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 +
'}';
}
}
??再看測(cè)試方法:
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.通過(guò)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());
}
}
??結(jié)果如圖:
從結(jié)果可以看到,第一步通過(guò)調(diào)用clone()方法后际歼,創(chuàng)建一個(gè)和student1一樣的新對(duì)象惶翻,但這只是淺拷貝,這從第二步就可以看出鹅心,當(dāng)改變student1的屬性時(shí)吕粗,student2也根本改變,而且通過(guò)hash值也能看出對(duì)象屬性的hash是一致的旭愧。
通過(guò)構(gòu)造函數(shù)實(shí)現(xiàn)復(fù)制
先給定一個(gè)實(shí)體類(lèi)
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 +
'}';
}
}
再給定測(cè)試類(lèi)
public static void main(String ...args) {
Age age = new Age(21);
Student2 student1 = new Student2(age,"小明");
//構(gòu)造函數(shù)
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);
//查看對(duì)象屬性的hash
System.out.println(student1.getAge().hashCode());
System.out.println(student2.getAge().hashCode());
}
結(jié)果如圖:
同樣可以看到與clone對(duì)象一樣的結(jié)果颅筋。
深復(fù)制
深復(fù)制一樣有兩種方式實(shí)現(xiàn):
- 序列化(serialization)這個(gè)對(duì)象,再反序列化回來(lái)输枯,就可以得到這個(gè)新的對(duì)象议泵,無(wú)非就是序列化的規(guī)則需要我們自己來(lái)寫(xiě)。
- 繼續(xù)利用 clone() 方法桃熄,既然 clone() 方法先口,是我們來(lái)重寫(xiě)的,實(shí)際上我們可以對(duì)其內(nèi)的引用類(lèi)型的變量瞳收,再進(jìn)行一次 clone()碉京。
繼續(xù)改寫(xiě)Age類(lèi),讓其實(shí)現(xiàn)Cloneable接口,同時(shí)改寫(xiě)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 + '\'' +
'}';
}
}
測(cè)試方法:
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.通過(guò)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());
}
}
結(jié)果:
可以看到,這次在改變student1的時(shí)候收夸,student2不會(huì)跟著改變。hash值也不一樣了血崭。