java中的三種拷貝方式
第一種 基本資料類型:
八大基本資料類型:
A a1 = a2
我們需要了解的是這實際上複制的是引用:
也就是說 a1 和 a2 指向的是同一個對象。是以,當 a1 變化的時候,a2 裡面的成員變量也會跟着變化。
第二種 淺拷貝:(複制引用但不複制引用的對象)
建立一個新對象,然後将目前對象的非靜态字段複制到該新對象,如果字段是值類型的,那麼對該字段執行複制;
如果該字段是引用類型的話,則複制引用但不複制引用的對象。是以,原始對象及其副本引用同一個對象。
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = stu1;
System.out.println("學生1:" + stu1.getNumber()); // 學生1:12345
System.out.println("學生2:" + stu2.getNumber()); // 學生2:12345
但是如果:
stu2.setNumber(54321);
System.out.println("學生1:" + stu1.getNumber()); // 學生1:54321
System.out.println("學生2:" + stu2.getNumber()); // 學生2:54321
因為 stu1 和 stu2 指向記憶體堆中同一個對象
解決方法:
被複制的類需要實作Clonenable接口
覆寫clone()方法,通路修飾符設為public。方法中調用super.clone()方法得到需要的複制對象,(native為本地方法)
@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone();
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return stu;
}
Student stu1 = new Student();
stu1.setNumber(12345);
Student stu2 = (Student)stu1.clone();
System.out.println("學生1:" + stu1.getNumber()); // 學生1:12345
System.out.println("學生2:" + stu2.getNumber()); // 學生2:12345
stu2.setNumber(54321);
System.out.println("學生1:" + stu1.getNumber()); // 學生1:12345
System.out.println("學生2:" + stu2.getNumber()); // 學生2:54321
但是又如果:
Address addr = new Address();
addr.setAdd("杭州市");
Student stu1 = new Student();
stu1.setNumber(123);
stu1.setAddr(addr);
Student stu2 = (Student)stu1.clone();
System.out.println("學生1:" + stu1.getNumber() + ",位址:" + stu1.getAddr().getAdd()); // 學生1:123,位址:杭州市
System.out.println("學生2:" + stu2.getNumber() + ",位址:" + stu2.getAddr().getAdd()); // 學生2:123,位址:杭州市
addr.setAdd("西湖區");
System.out.println("學生1:" + stu1.getNumber() + ",位址:" + stu1.getAddr().getAdd()); // 學生1:123,位址:西湖區
System.out.println("學生2:" + stu2.getNumber() + ",位址:" + stu2.getAddr().getAdd()); // 學生2:123,位址:西湖區
原因是淺複制隻是複制了addr變量的引用,将值複制後再将引用傳回給新對象,并沒有真正的開辟另一塊空間。
淺拷貝:BeanUtils.copyProperties(executiveSummary, executiveSummaryOld);
第三種 深拷貝:(複制對象和其應用對象)
深拷貝不僅複制對象本身,而且複制對象包含的引用指向的所有對象。
将Address類可複制化
然後在student類中:
@Override
public Object clone() {
Student stu = null;
try{
stu = (Student)super.clone(); //淺複制
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
stu.addr = (Address)addr.clone(); //深度複制
return stu;
}
// 學生1:123,位址:杭州市
// 學生2:123,位址:杭州市
// 學生1:123,位址:西湖區
// 學生2:123,位址:杭州市
或者序列化實作:
在 Java 語言裡深複制一個對象,常常可以先使對象實作 Serializable 接口,然後把對象(實際上隻是對象的一個拷貝)寫到一個流裡,再從流裡讀出來,便可以重建對象。