繁体   English   中英

对象Java的深层副本

[英]Deep copy of an object Java

我正在尝试克隆MyGraph的一个对象,我希望它是一个深层复制,因此对象内的arraylists也被克隆。 现在我有:

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

这会在尝试克隆arraylist时返回错误。 我不确定这是否是将arraylists添加到对象的正确方法。

ArrayListclone操作返回对象的浅表副本,并不适合您的目的。 手动解决方法是:

  1. 创建与源列表大小相同的目标数组列表
  2. 迭代源列表并将其每个项目的克隆创建到目标列表中

显然,这只有在数组列表包含实现clone项目时才有效,此外,项目clone操作实际上返回一个深层副本。 换句话说,它不能保证。 实际上,为Java对象实现深度克隆功能并不容易,请参考Java中的大量讨论:深度克隆/复制实例和其他SO线程的推荐解决方案,以了解可用的选项。 除了那里提供的答案,这里还有一些其他选择:

序列化

如果层次结构中的所有(必需的)对象都可以序列化,那么您可以使用这个简单的代码进行深度克隆:

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");
    }
}

请注意,某些深度克隆库将标准Java序列化与反射黑客和/或字节代码检测相结合,以使整个对象层次结构完全可序列化。 您可能需要也可能不需要。

复制工具

例如, Dozer提供快速深层复制功能。 Orika也可以实现相同的目标,尽管配置更多:

public MyGraph deepCopy() {
    final DozerBeanMapper mapper = new DozerBeanMapper();
    final QuicksortTest clone = mapper.map(this, MyGraph.class);
    return clone;
}

当然唯一的缺点是,您需要进入项目的额外依赖项。

上共有切线,您deepCopy方法应该是一成不变的。 此外,您应该认真考虑通过将其设置为私有并实现getter / setter来封装对象的状态。

您调用clone()每个类都必须实现Cloneable接口。 从您的评论中,我了解您的MyGraph类没有实现Cloneable接口。 在这种情况下, Object.clone()抛出CloneNotSupportedException

尝试使用cloning进行深层复制很复杂,因为您需要确保所有类都实现Cloneable接口并且它们具有clone()定义。

更好的方法是通过Copy Constructor or Serialization 这是我的博客 ,我已经详细讨论过它。 希望能帮助到你 :)

Java中克隆的一个基本概念问题[可以说基本问题]是像List<String>这样的类型的字段可能代表至少五个非常不同的东西:

  • 对可变列表的唯一现存引用,用于封装其可变状态,但是 - 作为唯一现存的引用 - 不会封装其标识(列表可以替换为包含相同项的不同列表,不改变程序的语义)。 包含此字段的对象的正确克隆将包含对包含相同项目的不同列表的引用。

  • 对可变列表的引用,虽然它允许自己进行变异,但它永远不会暴露于任何会实际变异的列表。 当其他代码不会改变列表或将其暴露给可能执行此操作的代码时,此引用才可与其他代码共享。 包含此字段的对象的正确克隆可以包含对原始列表或包含相同项的其他列表的引用。

  • 对不可变列表的引用。 此引用可以与其他代码自由共享,而不考虑该代码如何暴露它。 如上所述,包含此字段的对象的正确克隆可以包含对原始列表或副本的引用。

  • 对可变列表的引用,该列表由某个其他对象拥有,其目的是将其绑定到封装在列表中的另一个对象状态的那些方面。 保存该字段的对象的正确克隆必须包含对该相同列表的引用,而不是其副本。

  • 对此对象拥有的可变列表的引用,但其他对象也有一个引用,用于观察此对象的状态或向此对象提供信息。 保存此字段的对象无法单独正确克隆,但可以克隆一组相互连接的对象,并为新的对象集提供一组互连,这些互连与原始组中的对象同构。

该字段包含引用的对象的具体类型可以区分上述一些情况,但不能区分它们中的所有情况。 特别地,第一和第四场景在克隆方法上需要不同的行为,尽管在两种情况下引用都可能指向ArrayList<string>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM