Clone()vs Copy构造函数-在java中建议使用

Clone()vs Copy构造函数-在java中建议使用,java,clone,copy-constructor,Java,Clone,Copy Constructor,java中的克隆方法与复制构造函数。哪一个是正确的解决方案。在哪里使用每个案例?克隆已损坏,因此不要使用它 对象类的克隆方法 这是一种神奇的方法 任何纯Java方法都做不到的事情 do:它生成一个相同的 它的目标。它已经出现在 自 Java测试版发布日 编译器*;它就像所有古代的东西一样 魔法,需要适当的 咒语,以防止咒语 出人意料地适得其反 首选复制对象的方法 Foo copyFoo (Foo foo){ Foo f = new Foo(); //for all properties

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

克隆已损坏,因此不要使用它

对象类的克隆方法 这是一种神奇的方法 任何纯Java方法都做不到的事情 do:它生成一个相同的 它的目标。它已经出现在 自 Java测试版发布日 编译器*;它就像所有古代的东西一样 魔法,需要适当的 咒语,以防止咒语 出人意料地适得其反

首选复制对象的方法

Foo copyFoo (Foo foo){
  Foo f = new Foo();
  //for all properties in FOo
  f.set(foo.get());
  return f;
}
阅读更多

请记住,克隆不是开箱即用的。您必须实现Cloneable并覆盖在公共场合创建的clone方法

如其他答案所述,克隆方法有许多设计问题,复制构造函数需要手工操作,因此有一些备选方案更可取:

创建一个浅层克隆,如Object.clone创建的克隆。这个班是从哪里来的

创建深度克隆。i、 整个属性图是克隆的,不仅是第一级,而且所有类都必须实现可序列化

提供深度克隆,无需实现可序列化


另见:。在Java中,克隆是被破坏的,很难正确地实现它,即使这样做了,它也不能提供太多的功能,因此不值得这么麻烦。

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

// Need to clone person, which is type Person
Person clone = new Person(person);
如果person可以是person的子类,或者person是接口,那么这就不起作用。这就是克隆的全部意义,它可以在运行时动态克隆正确的类型,前提是克隆得到了正确的实现

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


现在,假定克隆得到了正确实现,那么person可以是任何类型的person。

克隆的设计有几个错误,请参见,因此最好避免它

Person clone = (Person)person.clone();
从,第11项:明智地覆盖克隆

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

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

他们不依赖于有风险的语言外物体创造机制 他们不要求不可强制执行地遵守记录很少的约定 它们与final字段的正确使用没有冲突 它们不会抛出不必要的已检查异常 他们不需要石膏。 所有标准集合都有副本构造函数。使用它们

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

非常悲哀:克隆/克隆和构造函数都不是很好的解决方案:我不想知道实现类!!!e、 g.-我有一个映射,我想复制它,使用相同的隐藏MumbleMap实现,如果支持的话,我只想复制一个。但是,唉,Cloneable上没有clone方法,因此您无法安全地键入cast来调用clone

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


当然,如果更多的库(如集合)是不可变的,那么这个复制任务就会消失。但是接下来我们将开始设计Java程序,使用类不变量,而不是VerdammtBean模式,创建一个破碎的对象并进行变异,直到性能良好为止.

不惜一切代价避免克隆,选择您自己的复制解决方案。复制构造函数比Object.clone更好,因为它们不会强制我们实现任何接口或引发任何异常,但如果需要,我们肯定可以做到,不需要任何强制转换,也不要求我们依赖未知的对象创建机制,不需要父类遵循任何约定或实现任何东西,允许我们修改最终字段,允许我们完全控制对象创建,我们可以在其中编写初始化逻辑。阅读更多,嗯,克隆没有被破坏。你认为这是为什么?如果这是因为如果不重写它,它就不能工作,那么,这就是它的契约。@Bozho,阅读有效的Java第二版,Bloch解释得很好。Doug Lea除了克隆阵列之外,甚至不再使用克隆。我真的不明白为什么克隆不能更简单。这是一种选择吗?或者说,在一般情况下,这背后确实存在着严重的问题?@Polygene说,我也没有使用克隆,这就是为什么我建议使用小海狸。但我的观点是
这个克隆人可以被使用,尽管是明智的。在简单的情况下,它工作得相当好。因此,让我们结束汽车比喻-这就像说,俄罗斯汽车的工作。我承认我还没有读过有效的Java,但我会说Cloneable作为一个接口的优势。也就是说,您可以将泛型类和函数的参数限制为只接受实现可克隆的类,然后只调用克隆。如果没有它,我不相信有一个好的方法来实现它,您可能会求助于反射来发现类的副本构造函数。这还假设,如果Foo有一个接受Foo的构造函数,那么它实际上就是一个复制构造函数。至少你知道克隆应该返回什么。不幸的是,有人曾经建议克隆的正确实现应该包含new而不是super.clone,因为克隆的正确行为是调用super.clone,如果该方法本身调用super.clone或者是对象的内置memberwise克隆;如果super.clone最终调用了new,那么clone唯一没有完全中断的行为就是调用new本身,但是每个子类都必须重写clone,这样子类是否需要重写clone。在大多数情况下,深与浅的问题在我看来并不含糊。存在一个SomeCollection来保存类型T的对象的标识,对其调用clone应该会生成一个相同类型的新实例,该实例与原始实例分离,但保存对相同T的引用。对原始或克隆所做的任何操作都不会影响存储在另一个克隆中的对象的标识。我真的不明白困惑是什么。深度克隆库是如何在任何对象上工作的?我闻到的代码可能充满了反射,很多反射:其中哪一个不复制引用和复制值?BeanUtils.cloneBeanbean正在复制引用,但我使用的是android版本android-java-air-bridge.jar,而不是原始的apache版本。我已经尝试了java深度克隆库,效果非常好!!它不复制引用:D,复制值当它可能是另一种类型的列表(例如LinkedList)时,您正在将原始文件复制为ArrayList。这正是克隆优于复制构造函数的原因。这类事情还有一些希望,至少对于您在项目中创建的值对象是这样的:如果复制很容易,它已经是Java的一部分了。但事实并非如此。你想要浅拷贝,深拷贝,还是介于两者之间?对于不同的类,您是否有不同的行为,这取决于您复制的内容和您要强制转换的内容?泛型会发生什么?当您复制的是泛型的参数时会发生什么?在没有继承和不可变的情况下,这可能更容易推理,但这些都是Java语言的核心。也许像Scala这样保证可变性的语言会使可克隆性变得更容易。@IceArdor-我想要一个浅拷贝,根据源代码对结果进行类型推断,并在内部使用相同的实现类。至少,如果源实现有一个默认构造函数,我想。@Roboprog你确定几年前写评论时浅层复制不起作用吗?浅薄的复制品对我来说几乎毫无意义。newMap=new HashMapoldMap在我真正需要浅层复制时工作。当您拥有从java.lang.Object继承的最后一个类时,就更容易正确操作。当类包含可变数据结构并因此需要deepcopy时,这是一个棘手的问题,但同样的挑战也会出现在副本构造函数中。