3

众所周知,它Cloneable已无法修复(有关更多信息,请参阅此问题中的讨论)。

关于替代方案和“我如何正确地做”的最后一个问题是几年前的:

所以我想再问一遍:

什么是现代(2014 年)的替代品Cloneable

我正在寻找一个通用的解决方案。我可以想象以下要求:

  • Copyable类将实现的某种接口: A extends Copyable.
  • 深度复制。如果一个 istanceA引用了 的一个实例Ba.copy()则应该引用一个新的b.copy().
  • 复制到指定目标:a.copyTo(a1).
  • 多态复制:如果Bextends Athen应该复制from toa.copyTo(b)的所有属性。Bab

当然我可以自己实现所有这些,但是为此拥有标准接口不是很合理吗?还是我错过了什么?


我的上下文的一些背景。我经常使用 JAXB 和模式派生类。对这些类进行深度复制通常非常有用。几年前,我编写了几个 JAXB 模式编译器插件来生成copyTo实现上述(以及更多)要求的方法。我不得不使用我自己的运行时 API。现在我正在重新审视这个案例,并决定询问是否有标准解决方案。

4

3 回答 3

4

我不止一次使用的机制是序列化/反序列化。当然,这仅在所有对象和元素都是可序列化的情况下才有效,因此并非在所有情况下都有效。如果所有对象都是可序列化的,那么它是一种非常有效的深度复制对象的方法。可以按如下方式完成:

public class SerializationHelper {
public static byte[] serialize(Object object) throws IOException {
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    new ObjectOutputStream(os).writeObject(object);
    return os.toByteArray();
}

@SuppressWarnings("unchecked")
public static <T> T deSerialize(byte[] array) throws IOException, ClassNotFoundException {
    return (T)new ObjectInputStream(new ByteArrayInputStream(array)).readObject();
}

@SuppressWarnings("unchecked")
public static <T> T clone(T object) {
    try {
        return (T)deSerialize(serialize(object));
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
于 2014-10-24T09:04:33.533 回答
2

首先,我不同意人们说这Cloneable是“破碎”。它没有“损坏”——它完全按照文档记录的方式执行,即Object.clone()引发或不引发异常。人们不喜欢它,因为他们认为它不是——他们认为它是可以克隆的对象的接口,而这从来都不是它应该做的。

Java(仍然)在标准库中没有可克隆对象的接口。如果他们添加这样的界面会很好,但他们没有。你可以制作自己的接口,也可以让自己的类实现它,但问题是你不能让现有的标准库类实现它。因此,仅当您只处理自己的类的生态系统时,这才有用。

于 2014-10-25T00:58:13.607 回答
0

最好的方法取决于情况和您的需求 - 您的性能限制是什么 - 如果您需要深/浅复制以及您的类对序列化的支持程度。

复制构造函数和工厂方法

仍然是一个有效的选择。当您需要深拷贝并且使用具有依赖关系的复杂对象时,编写它们可能非常复杂。虽然比序列化/反序列化快得多。

序列化/反序列化

可以很容易地实现,并且您可以轻松地将复杂的对象复制为深层副本。但是,您需要所有对象都是可序列化的,并且不会复制瞬态字段。此外,它比复制构造函数和其他变体更昂贵。

您不需要编写序列化/反序列化逻辑,因为已经有第三方库为此,例如:

Apache Commons Serialization Utils - 你可以调用SerializationUtils.clone()

反射

还有各种第三方工具使用反射来克隆。如果浅拷贝对您来说足够并且您遵循 JavaBeans 约定,您可以使用Apache Commons BeanUtils 。只要打电话BeanUtils.cloneBean()

如果您需要一个深拷贝,您可以使用例如:

我写了一篇比较上述方法的博客文章,您可以在其中找到更多详细信息。

于 2017-06-20T18:53:07.997 回答