克隆() vs 复制建构子——这是 java 中推荐的

克隆方法与 java 中的复制建构子,哪一个是正确的解决方案,在哪里使用?

185992 次浏览

克隆人坏了,所以不要用它。

Object 类的克隆方法 是一种有点神奇的方法 任何纯 Java 方法都无法做到的事情 做: 它产生一个完全相同的副本 它的目标。它一直存在于 原始对象超类,因为 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

请记住,clone()不是开箱即用的。您必须实现 Cloneable并覆盖 public中的 clone()方法。

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

参见: 如何正确重写克隆方法?。克隆在 Java 中被破坏了,它是 太难了来做正确的,甚至当它做 没什么用的时候,所以它真的不值得这么麻烦。

请记住,复制建构子将类的类型限制为复制建构子的类型:

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

现在,假设 clone得到了正确的实现,那么 person可以是任何类型的 Person

克隆()的设计有几个错误(参见 这个问题) ,因此最好避免它。

来自 有效的 Java 第二版第11项: 明智地覆盖克隆

考虑到与克隆人有关的所有问题,可以肯定地说 其他接口不应该扩展它,而类 为继承而设计的(第17项)不应实现它 它的许多缺点,一些专家程序员只是选择从来没有 覆盖克隆方法,并且永远不要调用它,除非,也许,调用 如果为继承设计类,请注意 如果您选择不提供行为良好的受保护的克隆方法,则 子类将不可能实现 Cloneable。

本书还描述了复制构造函数相对于可克隆/克隆构造函数的许多优势。

  • 它们不依赖于有风险倾向的语言外对象创建机制
  • 它们不要求对文件很少的约定的不可强制的遵守
  • 它们与最终字段的正确使用不冲突
  • 它们不会抛出不必要的检查异常
  • 他们不需要石膏。

所有标准集合都有复制构造函数。使用它们。

List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original);

巨大的悲哀: 无论是可克隆/克隆还是构造函数都不是伟大的解决方案: 我不想知道实现类! ! !(例如-我有一个地图,我想复制,使用相同的隐藏 MumbleMap 实现)我只是想做一个副本,如果这样做是支持的。但是,唉,Cloneable 上没有 Cloneable 方法,因此您无法安全地对其进行类型强制转换,从而无法调用 clone()。

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

当然,如果更多的库(例如-Collection)是不可变的,那么这个“复制”任务就会消失。但是接下来我们将开始使用“类不变量”而不是该死的“ bean”模式来设计 Java 程序(创建一个破碎的对象并进行变异直到足够好)。