Java 对象数组的深拷贝
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3947227/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Deep copy of an object array
提问by Snowman
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.
但是,由于某种原因,我上面的内容不起作用。我运行了自动化测试,但这些测试失败了。所以这里有一个错误,我不确定它是什么。
采纳答案by Stephen C
What you have implemented is a shallowcopy. To implement a deepcopy, you must change
你实现的是一个浅拷贝。要实现深拷贝,你必须改变
data[i] = other.data[i];
to some thing that assigns a copyof other.data[i]
to data[i]
. How you do this depends on the Position
class. Possible alternatives are:
到一些分配to副本的东西。你如何做到这一点取决于班级。可能的替代方案是:other.data[i]
data[i]
Position
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();
复制构造函数:
data[i] = new Position(other.data[i]);
工厂方法:
data[i] = createPosition(other.data[i]);
克隆:
data[i] = (Position) other.data[i].clone();
Notes:
笔记:
- 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.
- The
clone
approach will only work ifPosition
explicitly supports it, and this is generally regarded as an inferior solution. Besides, you need to be aware that the native implementation ofclone
(i.e. theObject.clone()
method) does a shallow copy.
- 上面假设复制构造函数、工厂方法和克隆方法分别实现了“正确”的复制,这取决于 Position 类;见下文。
- 该
clone
方法只有在Position
明确支持的情况下才会起作用,这通常被认为是一种较差的解决方案。此外,您需要注意clone
(即Object.clone()
方法)的本机实现是浅拷贝。
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.
事实上,在 Java 中实现深度复制的一般问题是复杂的。在Position
类的情况下,人们会假设属性都是原始类型(例如整数或双精度数),因此深拷贝与浅拷贝没有实际意义。但是如果有引用属性,那么你必须依靠复制构造函数/工厂方法/克隆方法来做你需要的那种复制。在每种情况下都需要对其进行编程。在一般情况下(您必须处理循环),这很困难并且需要每个类实现特殊方法。
There is one other potentialway 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:
还有另一种可能的方法来复制对象数组。如果数组中的对象是可序列化的,那么您可以通过使用ObjectOutputStream
和ObjectInputStream
序列化然后反序列化数组来复制它们。然而:
- this is expensive,
- it only works if the objects are (transitively) serializable, and
- the values of any
transient
fields won't be copied.
- 这个很贵
- 它仅在对象是(可传递的)可序列化时才有效,并且
transient
不会复制任何字段的值。
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.
总而言之,在 Java 中最好避免深度复制。
Finally, to answer your question about the Position
classes copy constructor works, I expect it is something like this:
最后,为了回答您关于Position
类复制构造函数的问题,我希望它是这样的:
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.
正如@Turtle 所说,不涉及魔法。您实现了一个构造函数(手动),它通过从现有实例复制来初始化其状态。
回答by Justin Ethier
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.
您只是在复制引用列表(假设这是一个对象数组)。如果要进行深拷贝,则需要使用new
为数组中的每个对象创建一个新实例。
回答by Thomas
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]);
您将需要为Position
(换句话说,Position 的构造函数接受另一个Position
并复制其中的原始数据)创建一个复制构造函数并说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.
基本上你的“深拷贝”构造函数PositionList
是一个拷贝构造函数,尽管拷贝构造函数确实倾向于表示一个深拷贝,所以deepCopy
参数是不必要的。
回答by D Patrick
This should make a "deep" copy
这应该是一个“深”副本
int [] numbers = { 2, 3, 4, 5};
int [] numbersClone = (int[])numbers.clone();
回答by Cazanator
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.
它仅适用于具有单个级别的对象的数组。