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

Clone() vs Copy constructor- which is recommended in java [duplicate]

提问人:Jothi 提问时间:3/12/2010 最后编辑:Jason NicholsJothi 更新时间:9/25/2013 访问量:193674

问:

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

java clone copy-constructor

评论

6赞 Bertrand Marron 3/12/2010
stackoverflow.com/questions/1106102/......
3赞 dimitarvp 3/12/2010
不惜一切代价避免,并选择自己的复制解决方案。clone
0赞 Naresh Joshi 1/12/2017
复制构造函数比 Object.clone() 更好,因为它们不会强迫我们实现任何接口或抛出任何异常,但如果需要,我们肯定可以这样做, 不需要任何强制转换, 不需要我们依赖未知对象创建机制, 不要求父类遵循任何约定或实现任何东西, 允许我们修改最终字段, 允许我们完全控制对象的创建,我们可以在其中编写我们的初始化逻辑。阅读更多 programmingmitra.blogspot.in/2017/01/...

答:

118赞 Tom 3/12/2010 #1

克隆已损坏,因此请勿使用它。

Object 类的 CLONE 方法 是一种有点神奇的方法,确实如此 任何纯 Java 方法都无法做到的 do:它生成一个相同的副本 它的对象。它已经存在于 primordial 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

评论

25赞 Bozho 3/12/2010
嗯,克隆没有坏。你认为这是为什么?如果是因为你不覆盖它,它就不起作用——好吧,这就是它的合同。
29赞 polygenelubricants 3/12/2010
@Bozho,阅读 Effective Java 第 2 版,Bloch 很好地解释了这一点。Doug Lea 除了克隆数组 (artima.com/intv/bloch13.html) 之外,甚至不再使用。clone()
2赞 LB40 3/12/2010
我真的不明白为什么克隆不能更简单。这是一个选择吗?还是在一般情况下,这背后真的存在严重的问题?
9赞 Bozho 3/12/2010
@polygenelubricants我也没有使用,这就是我建议使用 beanutils 的原因。但我的观点是,尽管可以“明智地”使用。在简单的情况下,它工作得很好。因此,让我们修改汽车的比喻 - 这就像说俄罗斯汽车有效。嗯,他们有,但不是很好。clone()clone()
8赞 spaaarky21 9/25/2014
我坦率地承认,我还没有读过《有效的Java》,但我会说Cloneable具有作为接口的优势。也就是说,你可以将泛型类和函数的参数限制为只接受实现 Cloneable 的类,然后直接调用 clone()。没有它,我不相信有一种(好的)方法来强制执行它,你可能会求助于反射来发现类的复制构造函数。这也假设,如果 Foo 有一个接受 Foo 的构造函数,它实际上是一个复制构造函数。至少你知道 clone() 应该返回什么。
58赞 Bozho 3/12/2010 #2

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

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

评论

1赞 Cruncher 12/9/2013
深度克隆库如何在任何对象上工作?我闻到的代码可能充满了反射
2赞 Bozho 12/10/2013
是的,很多反思:)
0赞 Ninja Coding 11/10/2016
以下哪项不复制引用和按值复制?BeanUtils.cloneBean(bean) 正在复制引用,但我使用的是 android 版本 (android-java-air-bridge.jar) 而不是原始 apache 版本。
0赞 Ninja Coding 11/10/2016
我尝试过 Java 深度克隆库,效果很好!它不会复制引用:D,复制值
3赞 polygenelubricants 3/12/2010 #3

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

评论

0赞 IceArdor 2/7/2018
当你有一个继承自 的类时,要容易得多。当类包含可变数据结构(因此需要深度复制)时,这很棘手,但同样的挑战也会出现在复制构造函数中。finaljava.lang.Object
19赞 Steve Kuo 2/17/2011 #4

请记住,复制构造函数将类类型限制为复制构造函数的类类型。请看以下示例:

// Need to clone person, which is type Person
Person clone = new Person(person);

如果可能是 的子类(或者是接口),则不起作用。这就是 clone 的全部意义所在,因为它可以在运行时动态克隆正确的类型(假设 clone 已正确实现)。personPersonPerson

Person clone = (Person)person.clone();

Person clone = (Person)SomeCloneUtil.clone(person); // See Bozho's answer

现在可以是正确实现的任何类型的假设。personPersonclone

评论

0赞 supercat 6/26/2012
不幸的是,有人曾经建议 clone 的正确实现应该涉及而不是 ,因为正确的行为是调用该方法本身调用(或者是对象的内置成员克隆);如果最终调用,则唯一没有完全中断的行为是调用自身,但是每个子类都必须重写以执行相同的操作,否则子类是否需要重写。newsuper.clone()clonesuper.clone()super.clone()super.clone()newclone()newclone()clone()
0赞 supercat 6/26/2012
在大多数情况下,“深与浅”的问题对我来说似乎并不模棱两可。A 的存在是为了保持类型事物的同一性,并且调用 one 应该会产生一个相同类型的新实例,该实例与原始实例分离,但包含对相同类型的引用。可以对原始对象或克隆对象执行的任何操作都不应影响存储在另一个对象中的对象的身份。我真的不明白什么是困惑。SomeCollection<T>Tclone()T
34赞 Rose Perrone 4/10/2012 #5

clone() 在设计时有几个错误(请参阅此问题),因此最好避免它。

摘自 Effective Java 第 2 版,第 11 项:明智地覆盖克隆

考虑到与 Cloneable 相关的所有问题,可以肯定地说 其他接口不应扩展它,并且类 为继承而设计(第 17 项)不应实现它。以 它有很多缺点,一些专家程序员干脆选择永远不这样做 重写 clone 方法,并且永远不要调用它,除非 复制数组。如果设计用于继承的类,请注意,如果 您选择不提供行为良好的受保护克隆方法,它 子类将无法实现 Cloneable。

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

  • 它们不依赖于容易出现风险的语言外对象创建机制
  • 他们并不要求无法强制遵守记录薄弱的公约
  • 它们与正确使用最终字段不冲突
  • 它们不会抛出不必要的检查异常
  • 他们不需要石膏。

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

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

评论

5赞 Steve Kuo 11/5/2015
您正在复制它可能是另一种类型的列表(例如)。这正是 clone 比复制构造函数更好的原因。originalArrayListLinkedList
2赞 Roboprog 9/25/2013 #6

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

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

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

评论

0赞 Roboprog 11/3/2016
这种事情是有希望的,至少对于你在项目中创建的值对象是这样:projectlombok.org/features/experimental/Wither.html
1赞 IceArdor 2/7/2018
如果复制很容易,那么它已经是 Java 的一部分了。但事实并非如此。你想要一个浅拷贝,一个深拷贝,还是介于两者之间?对于不同的职业,你是否有不同的行为,这取决于你要复制的内容和你要投射的内容?泛型会发生什么?当您复制的内容是泛型的参数时会发生什么情况?如果没有继承和可变性,这可能更容易推理,但这些都是 Java(语言)的核心。也许像 Scala 这样保证可变性的语言会让可克隆性变得更容易。
0赞 Roboprog 4/13/2018
@IceArdor - 我想要一个浅拷贝,根据源对结果进行类型推断,以及内部使用的相同实现类。至少,如果源代码实现有一个默认构造函数,我猜。
0赞 The incredible Jan 4/27/2018
@Roboprog 你确定几年前你写评论时浅层文案不起作用吗?浅暇的副本对我来说几乎毫无意义。newMap = new HashMap<>(oldMap) 在我真的只需要浅层副本时工作。