Cloneable的现代替代品?

时间:2014-10-24 09:02:11

标签: java clone cloneable

众所周知,Cloneable无法修复(请参阅讨论in this question了解更多信息)。

关于替代品的最后问题以及“我如何正确行事”已有几年了:

所以我想再问一遍:

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

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

  • 类将实现的某种Copyable接口:A extends Copyable
  • 深度复制。如果A的引用引用B的实例,则a.copy()应引用新的b.copy()
  • 复制到指定目标:a.copyTo(a1)
  • 多态复制:如果B延伸A,则a.copyTo(b)应将B的所有属性从a复制到b

当然,我可以自己实现所有这些,但是为此设置标准接口是不合理的?或者我错过了什么?


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

3 个答案:

答案 0 :(得分: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);
    }
}

答案 1 :(得分:2)

首先,我不同意人们说Cloneable已被打破&#34;。它不会被打破&#34; - 它完全按照文档记录的方式执行,这会导致Object.clone()抛出异常。人们不喜欢它,因为他们认为它不是 - 他们认为它是可以克隆的对象的接口,这绝不是它应该的样子。

Java(仍然)在标准库中没有可以克隆的对象的接口。如果他们添加这样的界面会很好,但他们还没有。您可以创建自己的接口,并且可以让自己的类实现它,但问题是您无法使现有的标准库类实现它。所以只有在你处理自己类的生态系统时才会有用。

答案 2 :(得分:0)

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

复制构造函数和工厂方法

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

<强>序列化/反序列化

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

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

Apache Commons Serialization Utils - 您只需致电SerializationUtils.clone()

<强>反射

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

如果您需要深层复制,可以使用例如:

我写了一个blog post来比较上面的方法,在那里你可以找到更多细节。