簡體   English   中英

對象數組的深拷貝

[英]Deep copy of an object array

我想使用構造函數制作對象數組的深層副本。

public class PositionList {
    private Position[] data = new Position[0];

public PositionList(PositionList other, boolean deepCopy) {
        if (deepCopy){
            size=other.getSize();
            data=new Position[other.data.length];
            for (int i=0;i<data.length;i++){
            data[i]=other.data[i];
            }

但是,由於某種原因,我上面的內容不起作用。 我運行了自動化測試,但這些測試失敗了。 所以這里有一個錯誤,我不確定它是什么。

你實現的是一個拷貝。 要實現拷貝,你必須改變

data[i] = other.data[i];

某些將other.data[i]副本分配給data[i] 您如何執行此操作取決於Position類。 可能的替代方案是:

  • 復制構造函數:

    data[i] = new Position(other.data[i]);

  • 工廠方法:

    data[i] = createPosition(other.data[i]);

  • 克隆:

    data[i] = (Position) other.data[i].clone();

筆記:

  1. 上面假設復制構造函數、工廠方法和克隆方法分別實現了“正確”的復制,這取決於 Position 類; 見下文。
  2. clone方法只有在Position明確支持它時才有效,這通常被認為是一種劣質的解決方案。 此外,您需要注意clone的本機實現(即Object.clone()方法)執行淺拷貝1

事實上,在 Java 中實現深度復制的一般問題是復雜的。 Position類的情況下,人們會假設屬性都是原始類型(例如 ints 或 doubles),因此深拷貝與淺拷貝沒有實際意義。 但是如果有引用屬性,那么你必須依靠復制構造函數/工廠方法/克隆方法來做你需要的那種復制。 在每種情況下都需要對其進行編程。在一般情況下(您必須處理循環),這很困難並且需要每個類實現特殊方法。

還有另一種可能的方法來復制對象數組。 如果數組中的對象是可序列化的,那么您可以通過使用ObjectOutputStreamObjectInputStream serialize 來復制它們,然后反序列化數組。 然而:

  • 這個很貴
  • 它僅在對象是(可傳遞的)可序列化時才有效,並且
  • 不會復制任何transient字段的值。

不建議通過序列化復制。 最好支持克隆或其他一些方法。

總而言之,在 Java 中最好避免深度復制。

最后,為了回答你關於Position類復制構造函數的問題,我希望它是這樣的:

public class Position {
    private int x;
    private int y;
    ...
    public Position(Position other) {
        this.x = other.x;
        this.y = other.y;
    }
    ...
}

正如@Turtle 所說,不涉及魔法。 您實現了一個構造函數(手動),它通過從現有實例復制來初始化其狀態。


1 - 指定clone()的 Object 實現執行淺拷貝,但這可能會被覆蓋。 clone的 javadoc 指定“合同”如下:

"創建並返回此對象的副本。"復制"的確切含義可能取決於對象的類。一般的意圖是,對於任何對象 x,表達式: x.clone() != x將是true,並且表達式: x.clone().getClass() == x.getClass()將是 true,但這不是絕對要求。雖然通常情況下是: x.clone().equals(x)為真,這不是絕對要求。”

“合同”中沒有任何內容涉及深復制與淺復制。 因此,如果您打算在此上下文中使用clone ,您需要知道實際的類clone方法的行為方式。

當你說:

data[i]=other.data[i];

您只是在復制引用列表(假設這是一個對象數組)。 如果要進行深拷貝,則需要使用new為數組中的每個對象創建一個新實例。

而不是說:

data[i]=other.data[i]

您需要為Position創建一個復制構造函數(換句話說,Position 的構造函數接受另一個Position並復制其中的原始數據)並說data[i]=new Position(other.data[i]);

基本上你的“深拷貝”構造函數PositionList是一個拷貝構造函數,雖然拷貝構造函數確實傾向於表示一個深拷貝,所以deepCopy參數是不必要的。

這是我使用的一個函數:

function copy(arr) {
  return arr
    .map(x => Object
      .keys(x)
      .reduce((acc, y) => {
        acc[y] = x[y]
        return acc
      }, {}))
}

它僅適用於具有單個級別的對象的數組。

這應該是一個“深”副本

int [] numbers = { 2, 3, 4, 5};

int [] numbersClone = (int[])numbers.clone();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM