Clone()vs Copy构造函数 - 在java中推荐

Jot*_*thi 137 java clone copy-constructor

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

Tom*_*Tom 109

克隆破了,所以不要使用它.

Object类的CLONE方法是一种有点神奇的方法,它可以执行纯Java方法无法做到的事情:它生成对象的相同副本.自Java编译器*发布以来,它一直出现在原始的Object超类中; 它和所有古代魔法一样,需要适当的咒语来防止法术意外地逆火

首选复制对象的方法

Foo copyFoo (Foo foo){
  Foo f = new Foo();
  //for all properties in FOo
  f.set(foo.get());
  return f;
}
Run Code Online (Sandbox Code Playgroud)

阅读更多 http://adtmag.com/articles/2000/01/18/effective-javaeffective-cloning.aspx

  • @Bozho,阅读_Effective Java 2nd Edition_,Bloch解释得很清楚.除了克隆数组(http://www.artima.com/intv/bloch13.html)之外,Doug Lea甚至不再使用`clone()`. (26认同)
  • 嗯,克隆没破.为什么你认为它是?如果是因为如果你不覆盖它就行不通 - 那就是它的合同. (21认同)
  • @polygenelubricants我也没有使用`clone()`,这就是我建议beanutils的原因.但我的观点是`clone()`_can_可以使用,但_"明智地"_.在简单的情况下,它工作得很好.所以让我们来修改汽车的比喻 - 就像说俄罗斯汽车的运作一样.嗯,他们这样做,但不是很好. (8认同)
  • 我承认我还没有(还)读过Effective Java但我会说Cloneable具有作为接口的优势.也就是说,您可以将泛型类和函​​数的参数限制为仅接受实现Cloneable的类,然后简单地调用clone().没有它,我不相信有一种(好)方法来强制执行它,你可能会使用反射来发现一个类的复制构造函数.这也假设如果Foo有一个接受Foo的构造函数,那**实际上是**复制构造函数.至少你知道clone()应该返回什么. (8认同)
  • 我真的不明白为什么克隆不能简单.这是一个选择吗?或者在一般情况下背后真的存在严重问题? (2认同)

Boz*_*zho 55

请记住,clone()开箱即用不起作用.您必须实现Cloneable并覆盖clone()制作的方法public.

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

  • 是的,很多反思:) (2认同)

Ros*_*one 32

clone()设计有几个错误(见这个问题),所以最好避免它.

Effective Java 2nd Edition,第11项:明智地覆盖克隆

鉴于与Cloneable相关的所有问题,可以肯定地说其他接口不应该扩展它,并且为继承而设计的类(第17项)不应该实现它.由于它有许多缺点,一些专家程序员只是选择永远不要覆盖克隆方法,永远不要调用它,除非复制数组.如果您设计了一个继承类,请注意,如果您选择不提供行为良好的受保护克隆方法,则子类将无法实现Cloneable.

本书还介绍了复制构造函数相对于Cloneable/clone的许多优点.

  • 他们不依赖于易于冒险的语言外对象创建机制
  • 他们并不要求无法强制遵守精简文件的惯例
  • 它们与正确使用最终字段不冲突
  • 它们不会抛出不必要的已检查异常
  • 他们不需要演员阵容.

所有标准集合都有拷贝构造函数.使用它们.

List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original);
Run Code Online (Sandbox Code Playgroud)

  • 当它可能是另一种类型的列表(例如`LinkedList`)时,你正在将`original`复制为`ArrayList`.这正是克隆比复制构造函数更好的原因. (4认同)

Ste*_*Kuo 18

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

// Need to clone person, which is type Person
Person clone = new Person(person);
Run Code Online (Sandbox Code Playgroud)

如果person可以是Person(或者如果Person是接口)的子类,则这不起作用.这是克隆的全部要点,它可以在运行时动态克隆正确的类型(假设克隆已正确实现).

Person clone = (Person)person.clone();
Run Code Online (Sandbox Code Playgroud)

要么

Person clone = (Person)SomeCloneUtil.clone(person); // See Bozho's answer
Run Code Online (Sandbox Code Playgroud)

现在person可以是正确实现的任何类型的Person假设clone.