1. 程式人生 > >對象的復制

對象的復制

有一個 getaddr get 一段 www ble 慎用 nbsp 轉載

先放一段代碼

Point.java

 1 public class Point {
 2     private int i;
 3  
 4     public Point(int i) {
 5         this.i = i;
 6     }
 7  
 8     public int getI() {
 9         return i;
10     }
11  
12     public void setI(int i) {
13         this.i = i;
14     }
15 }

PointTest.java

 1 public class PointTest {
 2     public static void main(String[] args) {
 3         //創建一個Point對象,使用pa這個引用變量來指向它
 4         Point pa = new Point(5);
 5         //創建一個pb引用變量,將pa的值賦值給pb
 6         Point pb = pa;
 7         //改變pa中的屬性的值
 8         pa.setI(3);
 9         //顯示pb中的值
10         System.out.println(pb.getI());
11 } 12 }

輸出的值為:3

因為pa和pb指向的是同一個對象(地址),改變其中任何一個都會改變該對象的內容。
那麽如何做到分開呢?就是改變pa的時候不讓pb發生改變(一般用於設置中間變量),這裏就涉及到對象的復制。

淺拷貝

將Point類修改為Point2類:

 1 public class Point2 implements Cloneable {
 2     private int i;
 3  
 4     public Point2(int i) {
 5         this.i = i;
 6     }
 7  
 8     public
int getI() { 9 return i; 10 } 11 12 public void setI(int i) { 13 this.i = i; 14 } 15 16 @Override 17 public Object clone() throws CloneNotSupportedException { 18 return super.clone(); 19 } 20 }

Point2Test.java

public class Point2Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        //創建一個Point2對象,使用p2a這個引用變量來指向它
        Point2 p2a = new Point2(5);
        //創建一個新對象,它是p2a的克隆,然後將這個新對象的引用賦值個p2b
        Point2 p2b = (Point2)p2a.clone();
        //改變p2a中的屬性的值
        p2a.setI(3);
        //顯示p2b中的值
        System.out.println(p2b.getI());
    }
}

輸出的值為:5

p2a和p2b是內容相容的不同對象。
Object類中的clone方法將原始對象的每個數據域復制給目標對象:
1.如果一個數據域是基本類型,復制的就是它的值;
2.如果一個數據域是對象,那麽復制的就是它的引用。註意這裏是它的引用。
如果Point2類中有一個數據域Address類,那麽雖然p2a==p2b為假,但是p2a.address==p2b.address為真。
所以這稱之為淺拷貝。

深拷貝

Address類

 1 public class Address implements Cloneable {
 2     private String addressName;
 3  
 4     public String getAddressName() {
 5         return addressName;
 6     }
 7  
 8     public void setAddressName(String addressName) {
 9         this.addressName = addressName;
10     }
11  
12     @Override
13     public Object clone() throws CloneNotSupportedException {
14         return super.clone();
15     }
16 }

Point3類

 1 public class Point3 implements Cloneable {
 2     private int i;
 3     private Address address;
 4  
 5     public Point3(int i) {
 6         this.i = i;
 7     }
 8  
 9     public int getI() {
10         return i;
11     }
12  
13     public void setI(int i) {
14         this.i = i;
15     }
16  
17     public Address getAddress() {
18         return address;
19     }
20  
21     public void setAddress(Address address) {
22         this.address = address;
23     }
24  
25     @Override
26     public Object clone() throws CloneNotSupportedException {
27         Point3 p3 = null;
28         p3 = (Point3) super.clone();
29         p3.address = (Address) address.clone();
30  
31         return p3;
32     }
33 }

Point3Test.java

 1 public class Point3Test {
 2     public static void main(String[] args) throws CloneNotSupportedException {
 3         //初始化對象p3a
 4         Point3 p3a = new Point3(5);
 5         Address address = new Address();
 6         address.setAddressName("位置1");
 7         p3a.setAddress(address);
 8  
 9         //復制對象
10         Point3 p3b = (Point3) p3a.clone();
11  
12         //改變p3a的address
13         address.setAddressName("位置2");
14  
15         //輸出結果比較
16         System.out.println("p3a的i: " + p3a.getI() + " p3a的address: " +
17             p3a.getAddress().getAddressName());
18         System.out.println("p3b的i: " + p3b.getI() + " p3b的address: " +
19             p3b.getAddress().getAddressName());
20     }
21 }

結果如圖:

技術分享圖片

結論:如果在拷貝一個對象時,要想讓這個拷貝的對象和源對象完全彼此獨立,那麽在引用鏈上的每一級對象都要被顯式的拷貝。所以創建徹底的深拷貝是非常麻煩的,尤其是在引用關系非常復雜的情況下。

所以有了如下一點,阿裏巴巴Java開發手冊第四章第19條:
【推薦】慎用 Object 的 clone 方法來拷貝對象。
說明: 對象的 clone 方法默認是淺拷貝,若想實現深拷貝需要重寫 clone 方法實現屬性對象的拷貝。

參考資料:
https://www.cnblogs.com/dolphin0520/p/3700693.html
https://blog.csdn.net/u014727260/article/details/55003402

本文系原創,轉載請註明出處,謝謝。

對象的復制