java淺拷貝和深拷貝(基礎也是很重要的)
對象的copy你興許只是懵懂,或者是並沒在意,來了解下吧。
對於的github基礎代碼https://github.com/chywx/JavaSE
最近學習c++,跟java很是相像,在慕課網學習c++也算是重溫習了下java基礎
明白了當初講師一直強調java傳遞的話只有值傳遞,不存在引用傳遞,為什麽一直要重復這,既然只有值傳遞,為啥還強調不是引用傳遞
毛病啊這是
學了c++才知道,原來c++有值傳遞,引用傳遞的說法,但是java只是值傳遞
最簡單的理解就是對於方法調用
比如 f(int a,int b) 這是值傳遞,傳遞過來的值不會被修改。
再如 f(int &a,int &b)這是引用傳遞,傳遞過來的值會被修改
步入正軌,說一說java的淺拷貝(Shallow Copy)、深拷貝(Deep Copy)。
淺拷貝(Shallow Copy):①對於數據類型是基本數據類型的成員變量,淺拷貝會直接進行值傳遞,也就是將該屬性值復制一份給新的對象。因為是兩份不同的數據,所以對其中一個對象的該成員變量值進行修改,不會影響另一個對象拷貝得到的數據。②對於數據類型是引用數據類型的成員變量,比如說成員變量是某個數組、某個類的對象等,那麽淺拷貝會進行引用傳遞,也就是只是將該成員變量的引用值(內存地址)復制一份給新的對象。因為實際上兩個對象的該成員變量都指向同一個實例。在這種情況下,在一個對象中修改該成員變量會影響
通過示例來了解下,
一:
使用構造函數實現copy
public class Person {
public static void main(String[] args) {
Son s = new Son(10);
Person p1 = new Person("大海", s);
Person p2 = new Person(p1);
p1.setSonName("小海");
p1.getSon().setAge(12);
System.out.println( "p1:" + p1);// p1:Person [sonName=小海, son=Son [age=10]]
System.out.println("p2:" + p2);// p2:Person [sonName=大海, son=Son [age=10]]
}
private String sonName;
private Son son;
// 自定義拷貝函數
public Person(Person person) {
this.sonName = person.sonName;
this.son = person.son;
}
public Person(String sonName, Son son) {
super();
this.sonName = sonName;
this.son = son;
}
public String getSonName() {
return sonName;
}
public void setSonName(String sonName) {
this.sonName = sonName;
}
public Son getSon() {
return son;
}
public void setSon(Son son) {
this.son = son;
}
@Override
public String toString() {
return "Person [sonName=" + sonName + ", son=" + son + "]";
}
}
class Son {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Son(int age) {
super();
this.age = age;
}
@Override
public String toString() {
return "Son [age=" + age + "]";
}
}
結果
p1:Person [sonName=小海, son=Son [age=12]]
p2:Person [sonName=大海, son=Son [age=12]]
對於上面的實例,該person對象有兩個成員,一個基本類型,一個引用類型,結果是拷貝出來的對象,基本類型的那個成員真正的實現了copy。
二:
使用自帶的clone方法,需要實現cloneable接口,不然會
Exception in thread "main" java.lang.CloneNotSupportedException:
public class Person2 implements Cloneable {
public static void main(String[] args) throws CloneNotSupportedException {
Son2 son1 = new Son2(10);
Person2 person1 = new Person2("大海", son1);
Person2 person2 = (Person2) person1.clone();
person2.setSon2Name("小海");
person2.getSon2().setAge(12);
System.out.println(person1);
System.out.println(person2);
}
public Person2(String son2Name, Son2 son2) {
super();
this.son2Name = son2Name;
this.son2 = son2;
}
private String son2Name;
private Son2 son2;
public String getSon2Name() {
return son2Name;
}
public void setSon2Name(String son2Name) {
this.son2Name = son2Name;
}
public Son2 getSon2() {
return son2;
}
public void setSon2(Son2 son2) {
this.son2 = son2;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person2 [son2Name=" + son2Name + ", son2=" + son2 + "]";
}
}
class Son2 {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Son2 [age=" + age + "]";
}
public Son2(int age) {
super();
this.age = age;
}
}
結果:
Person2 [son2Name=大海, son2=Son2 [age=12]]
Person2 [son2Name=小海, son2=Son2 [age=12]]
使用自帶的copy實現淺拷貝
---------------------------------------------------------------------------------------------------
深拷貝
相對於淺拷貝而言,對於引用類型的修改,並不會影響到對應的copy對象的值。每一層的每個對象都進行淺拷貝=深拷貝。
一:
還是使用clone方法,只不過得手動重寫一下。
上代碼
public class Person3 implements Cloneable {
public static void main(String[] args) throws CloneNotSupportedException {
Son3 son1 = new Son3(10);
Person3 person1 = new Person3("大海", son1);
Person3 person2 = (Person3) person1.clone();
person2.setSon2Name("小海");
person2.getSon3().setAge(12);//修改對應的引用對象的值。
System.out.println(person1);
System.out.println(person2);
}
public Person3(String son2Name, Son3 son3) {
super();
this.son2Name = son2Name;
this.son3 = son3;
}
private String son2Name;
private Son3 son3;
public String getSon2Name() {
return son2Name;
}
public void setSon2Name(String son2Name) {
this.son2Name = son2Name;
}
public Son3 getSon3() {
return son3;
}
public void setSon3(Son3 son3) {
this.son3 = son3;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person3 clone = (Person3) super.clone();
clone.setSon3((Son3) clone.getSon3().clone());
return clone;
}
@Override
public String toString() {
return "Person3 [son2Name=" + son2Name + ", son3=" + son3 + "]";
}
}
class Son3 implements Cloneable {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Son2 [age=" + age + "]";
}
public Son3(int age) {
super();
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
結果:
Person3 [son2Name=大海, son3=Son2 [age=10]]
Person3 [son2Name=小海, son3=Son2 [age=12]]
方法二:
顯然對於多個對象的話,顯然就很吃力。可以使用另一種方式,
將對象序列化為字節序列後,默認會將該對象的整個對象圖進行序列化,再通過反序列即可完美地實現深拷貝。
public class Person4 implements Serializable {
public static void main(String[] args) throws CloneNotSupportedException, ClassNotFoundException, IOException {
Son4 son = new Son4(10);
Person4 person1 = new Person4("大海", son);
//通過序列化方法實現深拷貝
ByteArrayOutputStream bos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bos);
oos.writeObject(person1);
oos.flush();
ObjectInputStream ois=new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
Person4 person2=(Person4)ois.readObject();
person1.setSon4Name("小海");
person1.getSon4().setAge(12);
System.out.println(person1.toString());
System.out.println(person2.toString());
}
public Person4(String son4Name, Son4 son4) {
super();
this.son4Name = son4Name;
this.son4 = son4;
}
private String son4Name;
private Son4 son4;
public String getSon4Name() {
return son4Name;
}
public void setSon4Name(String son4Name) {
this.son4Name = son4Name;
}
public Son4 getSon4() {
return son4;
}
public void setSon4(Son4 son4) {
this.son4 = son4;
}
@Override
public String toString() {
return "Person4 [son4Name=" + son4Name + ", son4=" + son4 + "]";
}
}
class Son4 implements Serializable {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Son2 [age=" + age + "]";
}
public Son4(int age) {
super();
this.age = age;
}
}
這是實現序列化接口方案,nice.
perfect!!!到位
java淺拷貝和深拷貝(基礎也是很重要的)