对象 Java 的深拷贝
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15155108/
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 Java
提问by Paul
I am trying to clone an object of MyGraph and I want it to be a deep copy so the arraylists inside the object are also cloned. Right now I have:
我正在尝试克隆 MyGraph 的一个对象,我希望它是一个深层副本,以便对象内的数组列表也被克隆。现在我有:
public static MyGraph deepCopy(MyGraph G){
MyGraph Copy = (MyGraph) G.clone();
Copy.VertexG = (ArrayList<Integer>) G.VertexG.clone();
Copy.EdgeG = (ArrayList<String>) G.EdgeG.clone();
return Copy;
}
This returns an error when it tries to clone the arraylist. I am not sure if this is the right way to add the arraylists to the object.
当它试图克隆数组列表时,这将返回一个错误。我不确定这是否是将数组列表添加到对象的正确方法。
回答by Perception
The clone
operation in ArrayList
returns a shallow copy of the object, and will not be suitable for your purposes. The manual workaround is to:
中的clone
操作ArrayList
返回对象的浅拷贝,不适合您的目的。手动解决方法是:
- Create a target array list of the same size as the source list
- Iterate the source list and create a clone of each of it's items, into the target list
- 创建与源列表大小相同的目标数组列表
- 迭代源列表并将其每个项目的克隆创建到目标列表中
Obviously, this will only work if the array list contains items that implement clone
, and in addition that the items clone
operation actually returns a deep copy. In other words, its not guaranteed. Actually, implementing deep clone functionality for Java objects is not at all easy, refer to extensive discussions in Java: recommended solution for deep cloning/copying an instanceand other SO threads to get a feel for the options available. In addition to the answers provided there, here are some other options:
显然,这仅在数组列表包含实现 的项目时才有效clone
,并且项目clone
操作实际上返回了一个深拷贝。换句话说,它不能保证。实际上,为 Java 对象实现深度克隆功能并不容易,请参阅Java 中的广泛讨论:深度克隆/复制实例和其他 SO 线程的推荐解决方案,以了解可用选项。除了那里提供的答案外,还有一些其他选项:
Serialization
序列化
If all (the required) objects in your hierarchy can be serialized then you can use this simple code to do a deep clone:
如果您的层次结构中的所有(所需)对象都可以序列化,那么您可以使用以下简单代码进行深度克隆:
public MyGraph deepCopy() {
try {
final ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
final ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
oos.close();
final ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(baos.toByteArray()));
final MyGraph clone = (QuicksortTest) ois.readObject();
return clone;
} catch (final Exception e) {
throw new RuntimeException("Cloning failed");
}
}
Note that some deep-clone libraries combine standard Java serialization with reflection hacks and/or byte code instrumentation in order to make the entire object hierarchy fully serializable. You may, or may not, need that.
请注意,一些深度克隆库将标准 Java 序列化与反射黑客和/或字节码检测相结合,以使整个对象层次结构完全可序列化。您可能需要,也可能不需要。
Copy tools
复印工具
For example, Dozer, provide fast deep-copy functionality. Orikacan also achieve the same, albeit with more configuration:
例如Dozer,提供快速的深度复制功能。Orika也可以实现相同的功能,尽管需要更多配置:
public MyGraph deepCopy() {
final DozerBeanMapper mapper = new DozerBeanMapper();
final QuicksortTest clone = mapper.map(this, MyGraph.class);
return clone;
}
The only downside of course, being the additional dependencies you need to pull into your project.
当然,唯一的缺点是您需要拉入项目的额外依赖项。
On a total tangent, your deepCopy
method should notbe static. Also, you should seriously considering encapsulating the state of your object by making it private and implementing getters/setters.
上共有切线,你的deepCopy
方法应该不能是静态的。此外,您应该认真考虑通过将对象设为私有并实现 getter/setter 来封装对象的状态。
回答by kutschkem
Every class you call clone()
on has to implement the Cloneable
interface. From your comments, i understand your MyGraph
class does not implement the Cloneable
interface. In that case, Object.clone()
throws the CloneNotSupportedException
.
您调用的每个类clone()
都必须实现该Cloneable
接口。从您的评论中,我了解到您的MyGraph
课程没有实现该Cloneable
接口。在这种情况下,Object.clone()
抛出CloneNotSupportedException
.
回答by rai.skumar
Trying to do deep copy with cloning
is complicated as you need to ensure that all classes implement Cloneableinterface and they have clone()definition.
尝试进行深度复制cloning
很复杂,因为您需要确保所有类都实现Cloneable接口并且它们具有clone()定义。
Better way would be to do it through Copy Constructor or Serialization
. Here is my blogon which i have discussed it in detail. hope it helps :)
更好的方法是通过Copy Constructor or Serialization
. 这是我的博客,我已经详细讨论过它。希望能帮助到你 :)
回答by supercat
A fundamental conceptual problem with cloning in Java [arguably thefundamental problem] is it's possible for a field of a type like List<String>
to represent at least five very different things:
Java 中克隆的一个基本概念问题 [可以说是基本问题] 是一种类型的字段可能List<String>
表示至少五种非常不同的事物:
The onlyextant reference to a mutable list, which is used to encapsulate the mutable state thereof, but which--being the only extant reference--would not encapsulate its identity (the list could be replaced with a different list holding the same items, without altering the program's semantics). A correct clone of the object that contains this field would hold a reference to a different list holding the same items.
A reference to a mutable list which, while it would allow itself to be mutated, will never be exposed to anything that would actually mutate it. This reference may be shared with other code onlyif that other code will refrain from mutating the list or exposing it to code that might do so. A correct clone of the object that contains this field could hold a reference to either the original list or a different list holding the same items.
A reference to an immutable list. This reference may be shared freely with other code without regard for how that code might expose it. As above, the correct clone of the object containing this field could hold a reference to either the original list or a copy.
A reference to a mutable list which is owned by some other object, which is held for purpose of binding this to those aspects of the other object's state which are encapsulated in the list. A correct clone of the object holding the field must hold a reference to that same list, and not a copy thereof.
A reference to a mutable list which this object owns, but to which other objects also have a reference for purpose of either observing this object's state, or feeding information to this object. The object holding this field cannot be correctly cloned in isolation, though it might be possible to clone a group of inter-connected objects and give the new set of objects a set of interconnections which was isomorphic to those in the original group.
对可变列表的唯一现存引用,用于封装其可变状态,但它——作为唯一现存引用——不会封装它的身份(列表可以被替换为包含相同项目的不同列表,不改变程序的语义)。包含此字段的对象的正确克隆将持有对包含相同项目的不同列表的引用。
对可变列表的引用,虽然它允许自身发生变异,但永远不会暴露于任何会真正改变它的东西。仅当其他代码不会改变列表或将其暴露给可能这样做的代码时,才可以与其他代码共享此引用。包含此字段的对象的正确克隆可以包含对原始列表或包含相同项目的不同列表的引用。
对不可变列表的引用。该引用可以与其他代码自由共享,而不管该代码如何公开它。如上所述,包含该字段的对象的正确克隆可以保存对原始列表或副本的引用。
对某个其他对象拥有的可变列表的引用,持有该列表是为了将 this 绑定到封装在列表中的其他对象状态的那些方面。持有该字段的对象的正确克隆必须持有对同一列表的引用,而不是其副本。
对这个对象拥有的可变列表的引用,但其他对象也有一个引用,目的是观察这个对象的状态,或者向这个对象提供信息。拥有该字段的对象不能单独正确地克隆,尽管可以克隆一组相互连接的对象,并为新的一组对象提供一组与原始组中的对象同构的互连。
The concrete type of the object to which the field holds a reference may distinguish between some of the above cases, but it cannot distinguish among all of them. In particular, the first and fourth scenarios require different behavior on the part of the cloning method, despite the fact that in both scenarios the reference might likely pointing to an ArrayList<string>
.
字段所引用的对象的具体类型可以区分上述一些情况,但不能区分所有情况。特别是,第一个和第四个场景需要克隆方法方面的不同行为,尽管在这两个场景中,引用可能指向一个ArrayList<string>
.