繁体   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