众所周知,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。现在我正在重新审视此案,并决定询问是否有标准解决方案。
答案 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来比较上面的方法,在那里你可以找到更多细节。