基本資料型別引用資料型別特點
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}*/
}
}