java中的克隆方法与复制构造函数。哪一个是正确的解决方案。在哪里使用每个案例?
答案 0 :(得分:103)
克隆破了,所以不要使用它。
Object类的CLONE方法 这是一种有点神奇的方法 什么都没有纯Java方法 do:它生成相同的副本 它的目标。它一直存在于 自从的原始Object超类 Java的Beta发布日 编译器*;就像所有古代人一样 魔术,需要适当的 咒语来阻止咒语 意外地回火
首选复制对象的方法
Foo copyFoo (Foo foo){
Foo f = new Foo();
//for all properties in FOo
f.set(foo.get());
return f;
}
了解更多 http://adtmag.com/articles/2000/01/18/effective-javaeffective-cloning.aspx
答案 1 :(得分:53)
请注意clone()
不能开箱即用。您必须实施Cloneable
并覆盖clone()
中的public
方法。
有一些替代方案,这是更可取的(因为clone()
方法有很多设计问题,如其他答案中所述),并且复制构造函数需要手动工作:
BeanUtils.cloneBean(original)
创建一个浅层克隆,就像Object.clone()
创建的那样。 (此课程来自commons-beanutils)
SerializationUtils.clone(original)
创建了一个深层克隆。 (即整个属性图被克隆,不仅是第一级)(来自commons-lang),但所有类都必须实现Serializable
Java Deep Cloning Library提供深度克隆而无需实施Serializable
答案 2 :(得分:32)
clone()设计有几个错误(见this question),所以最好避免它。
从Effective Java 2nd Edition,第11项:明智地覆盖克隆
考虑到与Cloneable相关的所有问题,可以说是安全的 其他接口不应该扩展它,以及那些类 为继承而设计(第17项)不应该实现它。因为 它的许多缺点,一些专家程序员只是选择永远不会 覆盖克隆方法,永远不要调用它,除非可能 复制数组。如果您设计了一个继承类,请注意if 你选择不提供一个行为良好的受保护克隆方法 子类不可能实现Cloneable。
本书还介绍了复制构造函数相对于Cloneable / clone的许多优点。
所有标准集合都有复制构造函数。使用它们。
List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original);
答案 3 :(得分:18)
请记住,复制构造函数将类类型限制为复制构造函数的类型。考虑一下这个例子:
// Need to clone person, which is type Person
Person clone = new Person(person);
如果person
可能是Person
的子类(或Person
是接口),则此操作无效。这是克隆的全部要点,它可以在运行时动态克隆正确的类型(假设克隆已正确实现)。
Person clone = (Person)person.clone();
或
Person clone = (Person)SomeCloneUtil.clone(person); // See Bozho's answer
现在person
可以是任何类型的Person
,假设clone
已正确实施。
答案 4 :(得分:3)
另见:How to properly override clone method?。克隆在Java中被打破了,如此努力以使其正确,即使它确实存在也没有提供太多,所以它并不值得麻烦。< / p>
答案 5 :(得分:2)
非常悲伤:Cloneable / clone和构造函数都不是很好的解决方案:我不想知道实现的类!!! (例如 - 我有一个Map,我想复制,使用相同的隐藏MumbleMap实现)我只想制作一个副本,如果这样做是支持的。但是,唉,Cloneable上没有克隆方法,因此没有什么可以安全地进行类型转换来调用clone()。
无论最好的“复制对象”库是什么,Oracle都应该将它作为下一个Java版本的标准组件(除非它已经隐藏在某个地方)。
当然,如果更多的库(例如 - 集合)是不可变的,那么这个“复制”任务就会消失。但是后来我们开始用“类不变量”而不是verdammt“bean”模式设计Java程序(制作一个破碎的对象并变异直到好[足够])。