141

java中的克隆方法与复制构造函数。哪一个是正确的解决方案。每个案例在哪里使用?

4

6 回答 6

116

克隆已损坏,所以不要使用它。

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

于 2010-03-11T19:19:24.553 回答
55

请记住,clone()开箱即用是行不通的。您将必须实现Cloneable并覆盖clone()public.

有一些替代方案更可取(因为该clone()方法有很多设计问题,如其他答案中所述),并且复制构造函数需要手动工作:

于 2010-03-11T19:22:43.880 回答
34

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);
于 2012-04-10T15:19:44.947 回答
19

请记住,复制构造函数将类类型限制为复制构造函数的类型。考虑这个例子:

// 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

于 2011-02-17T07:13:34.133 回答
3

另请参阅:如何正确覆盖克隆方法?. 克隆在 Java 中被破坏了,很难做到正确,即使做到了,它也没有真正提供太多,所以真的不值得麻烦。

于 2010-03-11T19:48:35.780 回答
2

非常悲伤:Cloneable/clone 和构造函数都不是很好的解决方案:我不想知道实现类!!!(例如 - 我有一个地图,我想复制它,使用相同的隐藏 MumbleMap 实现)我只想制作一个副本,如果支持的话。但是,唉,Cloneable 上没有 clone 方法,所以没有什么可以安全地类型转换来调用 clone()。

无论有什么最好的“复制对象”库,Oracle 都应该将其作为下一个 Java 版本的标准组件(除非它已经存在,隐藏在某个地方)。

当然,如果更多的库(例如 - Collections)是不可变的,那么这个“复制”任务就会消失。但是随后我们将开始使用诸如“类不变量”之类的东西而不是verdammt“bean”模式(制作一个损坏的对象并变异直到好[足够])来设计Java程序。

于 2013-09-25T03:20:00.387 回答