浅拷贝真的有必要吗?

11

我目前正在为Java编写一个图形库。正如您所期望的那样,存在一个Vertex类。该类包含一个VertexData<T>类型的对象,它本身可以包含任何内容。
(我知道这可能是多余的,我可以只做Vertex<T>,但出于问题的目的,这并不重要)。
我让VertexData<T>实现了Cloneable,并拥有一个public VertexData<T> clone()方法,通过序列化和反序列化调用Object来返回深度副本,就像此处描述的那样。

现在的问题是,既然我有一个深度复制方法,是否也有意义拥有一个浅层复制?如果有的话,在什么情况下浅层复制会优于深度复制?

更新:由于大多数答案和评论在某种程度上都包含了浅层复制的一些解释,我感觉我必须澄清一下。我知道什么是浅层复制,它是如何工作的,所有的一切。我的问题是,既然这是一个,并且我已经创建了一个深度复制方法,是否有意义提供一个浅层复制的方法?

我还要在此添加,在VertexData<T>类中不包含原始类型。
因此,在用于存储图形库中的顶点数据的容器类的上下文中,是否需要浅层复制?
如果需要,请在我正在开发的上下文中给出一个例子。
如果不需要,我是否应该仅为完整性而添加浅层复制方法?
这是一个好习惯还是无关紧要的?


4
浅拷贝在你想要复制共享一个大型底层数据结构或数据集的类时非常有用。例如,在一种情况下,如果你有多个“客户端”类都引用同一个大数据结构引用,并且你想要复制客户端,深拷贝会尝试复制底层数据,这可能不是你想要的。 - Ryan J
这取决于情况。浅复制通常意味着只复制对象的一层,而深复制通常意味着复制多层的所有内容。 - Adam
通常情况下,如果您引用不可变对象,您会创建浅拷贝,但这只是一个示例,而不是一个规则。 - biziclop
4个回答

3
这实际上取决于需求。如果您的对象不仅有原始字段,还应该(而且幸运的是确实)有一个“深拷贝”。在使用“浅层”或“深层”拷贝时没有“硬性规定”。由于它是“基于需求”的,因此像@RyanJ在对另一个答案的评论中指出的那样,提供两者是安全的。
如果您希望浅复制集合或对象,并更改一个属性,则会更改引用以及复制的对象。另一方面,如果您希望进行深度复制并能够更改对象或对象副本的值而不影响副本和原始数据,则只需要进行深度复制。这完全取决于需求以及您需要对象/系统执行的操作。我的最终建议是两者都要做。

3
List<Point>这样的容器类型有时可以用于保存一堆X、Y坐标对,但在其他情况下可能用于识别一堆可移动点,这些点被其他代码使用。前一种情况可以分为子情况,其中List<Point>的所有者也是其中Point实例的独占所有者,并且可以随意修改它们,或者所有者永远不会修改那些实例,但可能与承诺不修改它们的代码共享对它们的引用。
如果List<Point>用于封装(X,Y)坐标对,但所有者可能修改其中包含的Point对象,则正确的List<Point>克隆必须持有对所涉及Point对象的副本的引用。如果它封装了坐标对,但没有人会修改其中的对象(并且克隆列表的接收者不会向任何可能修改它们的代码公开对其中的对象的引用),则List<Point>的适当克隆可以持有对原始Point对象或其副本的引用;前者速度更快,但后者仍然是语义上正确的。
如果List<Point>用于识别其他代码可能修改的Point实例,并且任何这样的修改都需要反映在List<Point>本身中,则适当的克隆必须持有对与原始列表相同的Point对象的引用。如果一个克隆品代替持有那些Point对象的副本,那么它将不再持有与原始列表相同的语义信息。
如果Java根据它们是否仅使用独占拥有的可变实例或共享的不可变实例来分离集合类型,或者它们是否用于识别其中的内容,则可以拥有单个"克隆"概念,而不是要求"深度"和"浅层"克隆。然而,由于没有这种集合类型之间的区别,因此需要克隆方法,根据集合中的内容执行所需的操作。

1

在某些情况下是必需的。您可以根据以下几点推断出需求。

如果对象只有基本字段,则应选择浅拷贝。

如果对象引用其他对象,则根据需求,应考虑浅拷贝或深拷贝。

如果引用未被修改,则不需要进行深拷贝。在这种情况下,应选择浅拷贝。

如果引用已被修改,则首选深拷贝。

浅拷贝:

enter image description here

浅复制可能会导致不希望的影响,如果值元素从其他引用被更改。
深复制:

enter image description here

在深拷贝期间,对于数组值所引用的任何更改都不会导致对数组数据所引用的更改。
您可以参考此链接了解更多相关内容和示例。

0

你不需要浅拷贝。浅拷贝只会将一个新的引用变量分配给你已经存在于内存中的对象。'='运算符就可以完成这项工作。如需更多细节,请查看此帖子 - 在Java中,什么是浅拷贝?


1
嗯,我知道什么是浅拷贝。我的问题更多的是,由于我正在开发一个库,是否有意义也拥有一个浅拷贝。如果深拷贝可用,那么这个东西是否会有用过。 - gkrls
3
我不同意......是否需要进行浅拷贝或深拷贝不应由库的实现者决定,而应由库的使用者决定。提供两种方法可以确保您的库在所有情况下都具有通用性。这并没有真正回答问题。 - Ryan J
不需要。使用您的库的人将使用“=”运算符来完成此操作。您不必提供它。只有当有人想要一个新的引用变量来保存内存时,才会首选浅复制。但是,如果您想要,可以提供一个名为public ClassName shallowCopy(){return new ClassName(); //more stuff;}的新方法,如果您想要进行与浅复制相关的更多操作,但是您不能限制您的库用户使用“=”运算符。 - zookastos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接