java中的克隆方法与复制构造函数。哪一个是正确的解决方案。每个案例在哪里使用?
6 回答
克隆已损坏,所以不要使用它。
Object 类的克隆方法是一种有点神奇的方法,它完成了纯 Java 方法无法做到的事情:它生成其对象的相同副本。自 Java 编译器的 Beta 版发布之日起,它就存在于原始的 Object 超类中*;和所有古代魔法一样,它需要适当的咒语来防止咒语意外适得其反
首选复制对象的方法
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
请记住,clone()
开箱即用是行不通的。您将必须实现Cloneable
并覆盖clone()
在public
.
有一些替代方案更可取(因为该clone()
方法有很多设计问题,如其他答案中所述),并且复制构造函数需要手动工作:
BeanUtils.cloneBean(original)
创建一个浅克隆,就像由Object.clone()
. (这个类来自commons-beanutils)SerializationUtils.clone(original)
创建一个深层克隆。(即整个属性图被克隆,不仅是第一级)(来自commons-lang),但所有类都必须实现Serializable
Java 深度克隆库提供深度克隆,无需实现
Serializable
clone() 的设计有几个错误(参见这个问题),所以最好避免它。
来自Effective Java 2nd Edition,第 11 条:明智地覆盖克隆
鉴于与 Cloneable 相关的所有问题,可以肯定地说其他接口不应该扩展它,并且为继承而设计的类(第 17 条)不应该实现它。由于它的许多缺点,一些专业程序员干脆选择从不覆盖 clone 方法并且从不调用它,除非可能是复制数组。如果您为继承设计一个类,请注意,如果您选择不提供行为良好的受保护克隆方法,子类将无法实现 Cloneable。
本书还描述了复制构造函数相对于 Cloneable/clone 的许多优点。
- 他们不依赖于容易冒险的语言外对象创建机制
- 他们不要求强制遵守记录薄弱的约定
- 它们与正确使用 final 字段不冲突
- 他们不会抛出不必要的检查异常
- 他们不需要演员表。
所有标准集合都有复制构造函数。使用它们。
List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original);
请记住,复制构造函数将类类型限制为复制构造函数的类型。考虑这个例子:
// 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
另请参阅:如何正确覆盖克隆方法?. 克隆在 Java 中被破坏了,很难做到正确,即使做到了,它也没有真正提供太多,所以真的不值得麻烦。
非常悲伤:Cloneable/clone 和构造函数都不是很好的解决方案:我不想知道实现类!!!(例如 - 我有一个地图,我想复制它,使用相同的隐藏 MumbleMap 实现)我只想制作一个副本,如果支持的话。但是,唉,Cloneable 上没有 clone 方法,所以没有什么可以安全地类型转换来调用 clone()。
无论有什么最好的“复制对象”库,Oracle 都应该将其作为下一个 Java 版本的标准组件(除非它已经存在,隐藏在某个地方)。
当然,如果更多的库(例如 - Collections)是不可变的,那么这个“复制”任务就会消失。但是随后我们将开始使用诸如“类不变量”之类的东西而不是verdammt“bean”模式(制作一个损坏的对象并变异直到好[足够])来设计Java程序。