对象数组的深拷贝

发布于 2024-09-27 13:17:59 字数 461 浏览 4 评论 0原文

我想使用构造函数制作对象数组的深层副本。

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];
            }

但是,由于某种原因,我上面的内容不起作用。我运行了自动化测试,但这些测试失败了。所以这里有一个错误,我不确定它是什么。

I want to make a deep copy of an object array using a constructor.

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];
            }

However, what I have above for some reason is not working. I have automated tests that I run, and its failing those tests. So theres an error an here that Im not sure what it is.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

瑾兮 2024-10-04 13:17:59

您所实现的是复制。要实现深层复制,您必须
更改

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] = (位置) other.data[i].clone();

注意:

  1. 上面假设复制构造函数、工厂方法和克隆方法分别实现了“正确”的类型复制次数,取决于职位类别;见下文。
  2. clone 方法只有在 Position 明确支持的情况下才有效,这通常被认为是一个较差的解决方案。此外,您需要注意 clone 的本机实现(即 Object.clone() 方法)会执行浅复制1

事实上,在Java中实现深复制的一般问题很复杂。对于Position 类,我们会假设属性都是原始类型(例如整型或双精度型),因此深复制与浅复制是没有意义的。但是如果存在引用属性,那么您必须依赖复制构造函数/工厂方法/克隆方法来执行您需要的那种复制。在每种情况下都需要对其进行编程。并且在一般情况下(必须处理循环)这很困难并且需要每个类实现特殊的方法。

还有另一种复制对象数组的潜在方法。如果数组中的对象是可序列化的,那么您可以通过使用ObjectOutputStreamObjectInputStream序列化和反序列化数组来复制它们。然而:

  • 这很昂贵,
  • 只有当对象可(传递)序列化时它才有效,并且
  • 任何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() 的对象实现执行浅复制,但这可能会被覆盖。 clone 的 javadoc 指定“契约”如下:

“创建并返回此对象的副本。“副本”的精确含义可能取决于对象的类。一般意图是,对于任何对象 x,表达式:< code>x.clone() != x 将为 true,并且表达式:x.clone().getClass() == x.getClass() 将为 true,但这些并不是绝对的要求。虽然通常情况下:x.clone().equals(x) 为 true,但这并不是绝对的要求。”

< super>“合同”中没有任何内容谈论深度复制与浅度复制。因此,如果您要在这种情况下使用 clone,您需要了解实际的类 clone 方法的行为方式。

What you have implemented is a shallow copy. To implement a deep copy, you must
change

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

to some thing that assigns a copy of other.data[i] to data[i]. How you do this depends on the Position class. Possible alternatives are:

  • a copy constructor:

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

  • a factory method:

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

  • clone:

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

Notes:

  1. The above assume that the copy constructor, factory method and clone method respectively implement the "right" kind of copying, depending on the Position class; see below.
  2. The clone approach will only work if Position explicitly supports it, and this is generally regarded as an inferior solution. Besides, you need to be aware that the native implementation of clone (i.e. the Object.clone() method) does a shallow copy1.

In fact the general problem of implementing deep copying in Java is complicated. In the case of the Position class, one would assume that the attributes are all primitive types (e.g. ints or doubles), and therefore a deep versus shallow copying is moot. But if there are reference attributes, then you have to rely on the copy constructor / factory method / clone method to do the kind of copying that you require. In each case it needs to be programmed in. And in the general case (where you have to deal with cycles) it is difficult and requires each class to implement special methods.

There is one other potential way to copy an array of objects. If the objects in the array are serializable, then you can copy them by using ObjectOutputStream and ObjectInputStream serialize and then deserialize the array. However:

  • this is expensive,
  • it only works if the objects are (transitively) serializable, and
  • the values of any transient fields won't be copied.

Copying by serialization is not recommended. It would be better to support cloning or some other method.

All in all, deep copying is best avoided in Java.

Finally, to answer your question about the Position classes copy constructor works, I expect it is something like this:

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

As @Turtle says, there's no magic involved. You implement a constructor (by hand) that initializes its state by copying from an existing instance.


1 - It is specified that the Object implementation of clone() does a shallow copy, but this may be overridden. The javadoc for clone specifies the "contract" as follows:

"Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object. The general intent is that, for any object x, the expression: x.clone() != x will be true, and that the expression: x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements. While it is typically the case that: x.clone().equals(x) will be true, this is not an absolute requirement."

Nothing in the "contract" talks about deep versus shallow copying. So if you are going to use clone in this context, you need to know how the actual classes clone method behaves.

夜巴黎 2024-10-04 13:17:59

当您说:

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

您只是复制引用列表(假设这是一个对象数组)。如果要进行深复制,则需要使用new为数组中的每个对象创建一个新实例。

When you say:

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

You are just copying a list of references (assuming this is an array of objects). If you want to make a deep copy, you need to use new to create a new instance of each object in the array.

浅浅 2024-10-04 13:17:59

而不是说:

data[i]=other.data[i]

您需要为 Position 创建一个复制构造函数(换句话说,一个 Position 的构造函数,它接受另一个 Position 并复制其中的原始数据)并说 data[i]=new Position(other.data[i]);

基本上你的“深层复制”构造函数 PositionList 是一个复制构造函数,尽管复制构造函数确实倾向于表示深层复制,因此不需要 deepCopy 参数。

Instead of saying:

data[i]=other.data[i]

You will want to make a copy constructor for Position (in other words, a constructor for Position that takes in another Position and copies the primitive data inside it) and say data[i]=new Position(other.data[i]);

Basically your "deep copy" constructor the PositionList is a copy constructor, although copy constructor does tend to indicate a deep copy, so the deepCopy parameter is unnecessary.

明月松间行 2024-10-04 13:17:59

这是我使用的一个函数:

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

它仅适用于具有单个级别的对象的数组。

Here is a function I use:

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

It only works on arrays with objects with a single level.

撑一把青伞 2024-10-04 13:17:59

这应该制作一个“深层”副本

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

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

This should make a "deep" copy

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

int [] numbersClone = (int[])numbers.clone();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文