Clone() vs Copy constructor-在java中推荐[重复]
Posted
技术标签:
【中文标题】Clone() vs Copy constructor-在java中推荐[重复]【英文标题】:Clone() vs Copy constructor- which is recommended in java [duplicate] 【发布时间】:2011-01-26 12:56:51 【问题描述】:java 中的克隆方法与复制构造函数。哪一个是正确的解决方案。每个案例在哪里使用?
【问题讨论】:
***.com/questions/1106102/… 避免clone
不惜一切代价,选择你自己的复制解决方案。
复制构造函数比 Object.clone() 更好,因为它们不会强制我们实现任何接口或抛出任何异常,但如果需要,我们当然可以这样做,不需要任何强制转换, 不要求我们依赖未知的对象创建机制, 不要求父类遵循任何契约或实现任何东西, 允许我们修改最终字段, 允许我们完全控制对象创建, 我们可以编写我们的初始化其中的逻辑。阅读更多programmingmitra.blogspot.in/2017/01/…
【参考方案1】:
克隆已损坏,请勿使用。
Object 类的克隆方法 是一种有点神奇的方法 没有纯 Java 方法可以做到的 do:它产生一个相同的副本 它的对象。它已经出现在 原始 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
【讨论】:
嗯,克隆没有损坏。为什么你认为它是?如果是因为如果你不覆盖它就不起作用 - 好吧,这就是它的合同。 @Bozho,阅读 Effective Java 2nd Edition,Bloch 解释得很好。除了克隆数组 (artima.com/intv/bloch13.html) 之外,Doug Lea 甚至不再使用clone()
。
我真的不明白为什么克隆不能更简单。这是一个选择吗?还是在一般情况下确实存在严重的问题?
@polygenelubricants 我也没有使用clone()
,这就是我建议使用beanutils 的原因。但我的观点是clone()
可以使用,尽管“明智地”。在简单的情况下,它工作得很好。所以让我们修改一下汽车的比喻——就像说俄罗斯汽车可以工作一样。嗯,他们有,但不是很好。
我坦率地承认我(还没有)读过 Effective Java,但我会说 Cloneable 具有作为接口的优势。也就是说可以限制泛型类和函数的参数只接受实现了Cloneable的类,然后直接调用clone()。没有它,我不相信有一种(好的)方法可以强制执行,您可能会诉诸反射来发现类的复制构造函数。这也假设如果 Foo 有一个接受 Foo 的构造函数,那么 is 实际上是一个复制构造函数。至少你知道 clone() 应该返回什么。【参考方案2】:
请记住,clone()
不能开箱即用。您将必须实现Cloneable
并覆盖public
中的clone()
方法。
有一些替代方案是可取的(因为clone()
方法有很多设计问题,如其他答案所述),并且复制构造函数需要手动工作:
BeanUtils.cloneBean(original)
创建一个浅克隆,就像Object.clone()
创建的一样。 (本课来自commons-beanutils)
SerializationUtils.clone(original)
创建深度克隆。 (即克隆整个属性图,不仅是第一级)(来自commons-lang),但所有类都必须实现Serializable
Java Deep Cloning Library 提供深度克隆,无需实现 Serializable
【讨论】:
深度克隆库如何在任何对象上工作?我闻到了可能充满反射的代码 是的,很多反思:) 以下哪个不复制引用和按值复制? BeanUtils.cloneBean(bean) 正在复制引用,但我使用的是 android 版本 (android-java-air-bridge.jar) 而不是原始 apache 版本。 我试过java深度克隆库,效果很好!!它不复制引用:D,复制值【参考方案3】:clone() 的设计有几个错误(参见this question),所以最好避免它。
来自Effective Java 2nd Edition,第 11 条:明智地覆盖克隆
考虑到与 Cloneable 相关的所有问题,可以肯定地说 其他接口不应该扩展它,并且类 为继承而设计的(第 17 条)不应该实现它。因为 它的许多缺点,一些专家程序员干脆选择从不 覆盖克隆方法并且永远不要调用它,除非,也许, 复制数组。如果您为继承设计一个类,请注意,如果 您选择不提供行为良好的受保护克隆方法,它 子类将不可能实现 Cloneable。
这本书还描述了复制构造函数相对于 Cloneable/clone 的许多优点。
它们不依赖于具有风险的语言外对象创建机制 他们不要求强制遵守记录薄弱的约定 它们与正确使用 final 字段没有冲突 它们不会抛出不必要的检查异常 它们不需要演员表。所有标准集合都有复制构造函数。使用它们。
List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original);
【讨论】:
您将original
复制为ArrayList
,而它可能是另一种类型的列表(例如LinkedList
)。这就是为什么 clone 比复制构造函数更好。【参考方案4】:
请记住,复制构造函数将类类型限制为复制构造函数的类型。考虑这个例子:
// 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
已正确实现。
【讨论】:
不幸的是,有人曾经建议克隆的正确实现应该涉及new
而不是super.clone()
,因为clone
的正确行为是调用super.clone()
,如果该方法本身调用super.clone()
(或者是对象的内置成员克隆);如果super.clone()
最终调用new
,则clone()
唯一不完全破坏的行为是调用new
本身,但是每个子类都必须覆盖clone()
否则需要覆盖clone()
。
在大多数情况下,“深与浅”的问题对我来说并不模棱两可。存在一个SomeCollection<T>
来保存T
类型的事物的身份,并且在其中调用clone()
应该会产生一个相同类型的新实例,该实例与原始实例分离但包含对相同的T
。对原始对象或克隆所做的任何事情都不会影响存储在另一个对象中的对象的身份。我真的不明白这是什么混乱。【参考方案5】:
另请参阅:How to properly override clone method?。克隆在 Java 中被破坏了,很难做到正确,即使做到了并没有真正提供太多,所以真的不值得麻烦。
【讨论】:
当你有一个继承自java.lang.Object
的 final
类时,更容易做对。当类包含可变数据结构(因此需要深度复制)时,这很棘手,但同样的挑战也会出现在复制构造函数中。【参考方案6】:
非常悲伤:Cloneable/clone 和构造函数都不是很好的解决方案:我不想知道实现类!!! (例如 - 我有一个要复制的地图,使用相同的隐藏 MumbleMap 实现)我只想制作一个副本,如果支持的话。但是,可惜的是,Cloneable 上没有 clone 方法,所以没有什么可以安全地类型转换来调用 clone()。
无论有什么最好的“复制对象”库,Oracle 都应该将其作为下一个 Java 版本的标准组件(除非它已经存在,隐藏在某个地方)。
当然,如果更多的库(例如 - 集合)是不可变的,那么这个“复制”任务就会消失。但随后我们会开始使用诸如“类不变量”之类的东西而不是verdammt“bean”模式来设计Java程序(制作一个损坏的对象并变异直到好[足够])。
【讨论】:
对这类事情有一些希望,至少对于您在项目中创建的值对象:projectlombok.org/features/experimental/Wither.html 如果复制很容易,它已经成为 Java 的一部分。但事实并非如此。您想要浅拷贝、深拷贝还是介于两者之间?根据您要复制的内容和要转换的内容,您是否对不同的类有不同的行为?泛型会发生什么?当您复制的是泛型的参数时会发生什么?如果没有继承和可变性,这可能更容易推理,但这些都融入了 Java(语言)的核心。也许像 Scala 这样保证可变性的语言会使可克隆性更容易。 @IceArdor - 我想要一个浅拷贝,对基于源的结果进行类型推断,并在内部使用相同的实现类。至少,如果源实现有一个默认构造函数,我猜。 @Roboprog 你确定你几年前写评论时浅拷贝不起作用吗?浅拷贝对我来说几乎没有意义。当我真的只需要浅拷贝时,newMap = new HashMap(oldMap) 可以工作。以上是关于Clone() vs Copy constructor-在java中推荐[重复]的主要内容,如果未能解决你的问题,请参考以下文章
pytorch中copy_()detach()data()和clone()操作区别小结