2013-08-02 46 views
1

我知道什麼是deep copyshallow copyhow to deep copy等,但我的主要疑問是何時深拷貝對象引用?或多久?何時使用對象引用的深層克隆?或多久?


方案1:
考慮一個代碼,完整的代碼,請參閱http://pastebin.com/WEgeBFNb

class Box{ 
     Position pos; 
     Box(Position p){ 
      pos = p;  
     } 
     Position getPosition(){ 
      return pos; 
     } 
    } 

並有main(),如:

public class Sample{ 
     public static void main(String args[]){ 
     Position pos = new Position(3,5); 
     Box box = new Box(pos);  
     pos.setX(5); 
     System.out.println(box.getPosition().getX()); 
      // Will print 5, but I want Box to retain its value 
     } 

我已經達到了上述要求:

Box(Position p){ 
      pos = new Position(p);  // Deep cloning 
     } 

然後我必須在Position拷貝構造函數太像:

Position(Position p){ 
    x = p.x; 
    y = p.y; 
    } 

但我的問題是:當使用深克隆?

場景2: 例如,考慮一個c#代碼。

List<Accounts> = Mysession.getAllAccounts();。在這裏,我預計返回對象中的更改不能反映在會話對象中。 (這種情況不僅在C#中,而且通常在任何oop語言中) 所以,如果我開始深度克隆,那麼這不是一件容易的事情,因爲它會上升到5個更深的對象,並且具有一個關係

再次,我知道得到確切的100%我必須深入克隆。同意。

  1. 什麼是比較常見的?返回參考或對象的副本?
  2. 我聽說,深度克隆是一個繁瑣的過程,必須避免。所以多久一次可以深入克隆?
  3. 您可以舉一些示例場景(代碼不需要)。
  4. 初始化像上面的box例子,必須使用克隆pos = new Position(p)?或正常分配pos = p
+0

如果您的值對象只包含System.ValueType作爲字段,您可以使用struct而不是class.so,那麼您可以簡單地使用pos = p而不是pos = new Position(p)。 – Frank59

+0

@ Frank59考慮另一個具有其他對象的「has-a」關係的類。說'新房(myroom)''這裏'房間'包含一個'盒子'。在這種情況下,在'房間'構造函數中,我必須像'this.box = new Box(room.getBox());'[深層克隆]或簡單地'this.box = room.getBox()'[參考複製]? –

+0

如果你使用的結構(框是結構)和ValueTypes(框字段是值類型和結構)只有你可以使用neBox = oldBox; (自動深度複製),但是如果您將Box作爲類或引用到Box字段中,則需要實施深度複製算法。閱讀更多http://msdn.microsoft.com/en-us/library/saxz13w4.aspx – Frank59

回答

1

面向對象編程的主要目的必須是一個對象保證它在任何時候處於一個leagal狀態。

因此,當您返回一個對象的引用,你應該想想:

  1. 在返回對象不變?
  2. 返回引用(主對象)的當前對象是否具有取決於返回對象的值?(派生或高速緩存的值)

可以對這些問題通過以下方式的答案反應:

返回的引用是一個不可變的對象(字符串,BigDecimal的等)

  1. 無需操作

返回的引用是一個muttable對象(數組,日期,等c。),但主對象具有NO導出值(例如,只有裝飾它)

  1. 無需操作

返回的引用是一個muttable對象(數組,日期等),以及主對象已導出的值

  1. 在返回對象之前製作對象的副本。如果副本很容易製作,並且不符合內存或耗時(這取決於您的非功能性要求),則這適用。

  2. 返回一個不可修改參考原始對象(如Collections.unmodifiable ...一樣)。

  3. 返回其檢測訪問返回的對象和通知有關這些變化的主要對象,使得主對象可以重新計算得到的值,它不會處於不一致狀態的代理。

問自己同樣的問題,當你得到一個對象引用。通過構造函數或方法調用。

1

,而不是「深」或「淺」克隆的角度來思考,而不是想什麼每個封裝的對象引用代表條款。假設某些類實例George的字段Foo保存了類型爲IList<String>的引用。這樣的字段可以表示至少五個不同的事情:

  • 到一個不可變型,用於封裝包含在其中的字符串而舉行的實例的引用。

  • 對一個對象實例的引用,該對象實例的類型可以是可變的,但永遠不會暴露給任何可能變異它的對象,以便封裝其中包含的字符串。

  • 這個唯一的引用在喬治的方法的調用堆棧之外的宇宙中的任何地方都存在於喬治用來封裝其狀態的可變列表中。

  • 對其內容可能改變的列表的引用,其形成的一些其他對象的可變狀態的一部分。該字段不用於封裝列表的內容,而是其身份

  • 對其內容可能更改的列表的引用,其內容被認爲是George狀態的一部分,並且存在外部持久引用。

如果Foo是前兩種類型,喬治的適當的複製可能有其Foo指到同一列表爲George.Foo,一個新落成的列表,它會一直保持相同的內容,或其他任何列表將始終保持相同的內容。如果它屬於第三種類型,則George的適當副本必須將其Foo指向一個新列表,該列表預裝了George.Foo中的項目副本。如果是第四種類型,則正確的副本必須具有其Foo參照相同的對象作爲George.Foo而不是涉及副本。如果是第五種類型,George不能孤立克隆。

如果列表項屬於可變類型(而不是String),則必須確定應用於列表中項目的五個用途中的哪一個,並將每個列表項目視爲一個字段。請注意,對於邏輯上不可變的類型,其中包含的任何引用都必須是可共享的。如果一個對象的正確行爲會要求它所持有的引用不是任何其他引用的目標,那麼這意味着只有一個引用應該存在於持有該引用的對象。