基本資料型別引用資料型別特點

1、基本資料型別的特點:直接儲存在棧(stack)中的資料

2、引用資料型別的特點:儲存的是該物件在棧中引用,真實的資料存放在堆記憶體裡

引用資料型別在棧中儲存了指標,該指標指向堆中該實體的起始地址。當直譯器尋找引用值時,會首先檢索其在棧中的地址,取得地址後從堆中獲得實體。

深拷貝與淺拷貝特點

淺拷貝只複製指向某個物件的指標,而不復制物件本身,新舊物件還是共享同一塊記憶體。但深拷貝會另外創造一個一模一樣的物件,新物件跟原物件不共享記憶體,修改新物件不會改到原物件。

當把一個物件賦值給一個新的變數時,賦的其實是該物件的在棧中的地址,而不是堆中的資料。也就是兩個物件指向的是同一個儲存空間,無論哪個物件發生改變,其實都是改變的儲存空間的內容,因此,兩個物件是聯動的。

淺拷貝是按位拷貝物件,它會建立一個新物件,這個物件有著原始物件屬性值的一份精確拷貝。如果屬性是基本型別,拷貝的就是基本型別的值;如果屬性是記憶體地址(引用型別),拷貝的就是記憶體地址 ,因此如果其中一個物件改變了這個地址,就會影響到另一個物件。即預設拷貝建構函式只是對物件進行淺拷貝複製(逐個成員依次拷貝),即只複製物件空間而不復制資源。

Java clone方法深拷貝與淺拷貝

clone淺拷貝

由CloneDemo類可以看出,沒有重寫clone方法,物件中的引用資料型別只是複製了該引用資料型別的引用,並沒有在記憶體空間中開闢空間複製該引用資料型別,即對該引用資料型別進行了淺拷貝而不是深拷貝。

package JDKSource.lang;

public class CloneDemo implements Cloneable {
private int num;
private String name;
private Helper helper; public CloneDemo() {
} public int getNum() {
return num;
} public void setNum(int num) {
this.num = num;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Helper getHelper() {
return helper;
} @Override
public String toString() {
return "CloneDemo{" +
"num=" + num +
", name='" + name + '\'' +
", helper=" + helper +
'}';
} public void setHelper(Helper helper) {
this.helper = helper;
} public static class Helper {
public int num; public Helper(int num) {
this.num = num;
} public int getNum() {
return num;
} public void setNum(int num) {
this.num = num;
} @Override
public String toString() {
return "Helper{" +
"num=" + num +
'}';
}
} public static void main(String[] args) throws CloneNotSupportedException {
CloneDemo d1 = new CloneDemo();
d1.setName("Jack");
d1.setNum(10);
d1.setHelper(new Helper(100));
CloneDemo d2 = (CloneDemo) d1.clone();
System.out.println(d1.name == d2.name);
System.out.println(d1.num == d2.num);
System.out.println(d1.helper == d2.helper);
d2.setNum(11);
d2.setName("json");
d2.getHelper().setNum(101);
System.out.println(d1.name);
System.out.println(d1.num);
System.out.println(d1.helper.toString());
System.out.println(d2.name);
System.out.println(d2.num);
System.out.println(d2.helper.toString());
/* Output:
true
true
true
Jack
10
Helper{num=101}
json
11
Helper{num=101}*/
}
}

clone深拷貝

對Helper類和CloneDemo都重寫clone方法:

CloneDemo重寫clone方法:

@Override
protected CloneDemo clone() throws CloneNotSupportedException {
CloneDemo clone = (CloneDemo1) super.clone();
clone.helper = helper.clone();
return clone;
}

Helper重寫clone方法:

@Override
protected Helper clone() throws CloneNotSupportedException {
Helper helper = null;
Helper clone = (Helper) super.clone();
return clone;
}

輸出結果:

結果顯示,對Helper類和CloneDemo都重寫clone方法後,實現了對引用資料型別Helper的深拷貝。

/*      Output:
true
true
false
Jack
10
Helper{num=100}
json
11
Helper{num=101}*/

完整程式碼:

package JDKSource.lang;

public class CloneDemo1 implements Cloneable {
private int num;
private String name;
private Helper helper; public CloneDemo1() {
} public int getNum() {
return num;
} public void setNum(int num) {
this.num = num;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Helper getHelper() {
return helper;
} @Override
protected CloneDemo1 clone() throws CloneNotSupportedException {
CloneDemo1 clone = (CloneDemo1) super.clone();
clone.helper = helper.clone();
return clone;
} @Override
public String toString() {
return "CloneDemo{" +
"num=" + num +
", name='" + name + '\'' +
", helper=" + helper +
'}';
} public void setHelper(Helper helper) {
this.helper = helper;
} public static class Helper implements Cloneable {
public int num; public Helper(int num) {
this.num = num;
} public int getNum() {
return num;
} public void setNum(int num) {
this.num = num;
} @Override
public String toString() {
return "Helper{" +
"num=" + num +
'}';
} @Override
protected Helper clone() throws CloneNotSupportedException {
Helper helper = null;
Helper clone = (Helper) super.clone();
return clone;
}
} public static void main(String[] args) throws CloneNotSupportedException {
CloneDemo1 d1 = new CloneDemo1();
d1.setName("Jack");
d1.setNum(10);
d1.setHelper(new Helper(100));
CloneDemo1 d2 = (CloneDemo1) d1.clone();
System.out.println(d1.name == d2.name);
System.out.println(d1.num == d2.num);
System.out.println(d1.helper == d2.helper);
d2.setNum(11);
d2.setName("json");
d2.getHelper().setNum(101);
System.out.println(d1.name);
System.out.println(d1.num);
System.out.println(d1.helper.toString());
System.out.println(d2.name);
System.out.println(d2.num);
System.out.println(d2.helper.toString());
/* Output:
true
true
false
Jack
10
Helper{num=100}
json
11
Helper{num=101}*/
}
}