你知道 Java 中 clone 方法是怎么工作的吗?

励志文章 阅读(1026)
博e百国际网上娱乐

译文:刘志军

原文:

翻译:

clone()方法是Object类下的一个方法,它提供克隆机制创建的对象的副本。理解Java的克隆机制并不容易,因此我们首先解释克隆方法的工作原理,然后解释如何覆盖克隆方法,最后解释深度和浅层克隆。

什么是克隆对象

clone()方法返回的对象称为原始对象的克隆。克隆对象的基本特征必须是:obj.clone()!=obj,即克隆对象和原始对象是java堆中的两个独立对象。 Obj.clone()。getClass()==obj.getClass()和clone.equals(obj),这意味着克隆的对象完全是原始对象的副本。这些基本功能要求我们遵守克隆方法,因此重写克隆通常会覆盖equals方法。

克隆方法如何工作?

Object提供默认的克隆方法实现,它被声明为protected和native。所以它的实现依赖于本机代码,因为它承诺通过调用super.clone()方法返回对象,并且任何克隆的进程最终都会到达java.lang.Object的clone()方法,该方法首先检查这个related该类是否实现了Cloneable接口,该接口是一个标记接口。如果实例未实现可克隆接口,则抛出CloneNotSupported异常。此异常是已检查的异常,这意味着在克隆对象时始终需要处理它。如果没有抛出异常,那么java.lang.Object的clone()方法将创建一个副本并将其返回给调用者。因为Object类的clone()方法通过创建新对象生成此副本,然后逐字段生成,类似于赋值操作,此操作用于基元和不可变类型(不可变)。 )没关系,但是如果你的类包含一些变量数据结构,例如:ArrayList或者数组不合适,在这种情况下原始对象和复制对象将指向同一个堆,你可以通过深度克隆技术调用来防止这种情况发生发生。他的每个变量字段都是独立克隆的。简而言之,以下摘要是克隆方法的工作原理。

1.在实例上调用clone()的任何类都将实现克隆方法的可克隆覆盖以创建副本。

95317b8f145c4227a39f1028f5ef1ded

2.在Rectangle中调用clone方法被委托给super.clone(),它可以是自定义超类或默认的java.lang.Object。

4366a53f9f23482c88583645898f87d1

当调用java.lang.Object的clone()的最后一次调用时,它会验证关联的类是否实现了Cloneable接口,如果没有实现,则抛出CloneNotSupportedException,否则它会创建一个field-by-field的副本。

因此,为了使clone()方法正常工作,会发生两件事:类必须实现Cloneable接口,并且必须重写clone方法。这是最简单的例子。对于更复杂的对象,它包含多个文件,数组,将不可变对象与基本类型组合在一起,让我们看一下第二个克隆教程。

克隆()示例

在本文中,我们没有看到一种复杂的方法来覆盖clone,因为我们的Rectangle类非常简单,只包含本机类型,只需克隆通过Object的clone方法即可。但是下面的例子对于理解对象的克隆非常重要,这里是完整的代码:

fb537fe919974e868b1940f78c931a99

从输出中,您可以清楚地看到克隆对象具有与原始对象相同的属性,并且更改原始对象的属性不会影响复制对象的状态。因为它们只包含本机字段,包括任何可变对象都会影响它们,所以您还可以看到标准克隆对象的属性,例如:clone!=original,clone.getClass()==original.getClass(),clone .equals(原版的)。

要记住的事情

1.克隆方法用于创建对象的副本。要使用clone方法,该类必须实现java.lang.Cloneable接口以覆盖受保护的方法clone,如果未实现Clonebale接口,则会抛出CloneNotSupportedException。

2.克隆java对象时不调用构造函数。

3,java提供了一个浅拷贝(浅拷贝)默认方法来实现克隆,创建一个对象的副本然后通过赋值复制内容,这意味着如果你的类包含可变对象,那么原始对象和克隆将指向相同的内部对象,这是非常危险的,因为可变字段上发生的任何更改都将反映在原始对象和复制对象上。要避免这种情况,请覆盖clone()方法。

4.根据惯例,实例的克隆应该通过调用super.clone()获得,这有助于克隆对象的不变性构建为:clone!=original和clone.getClass()==original。 getClass(),虽然这些都不是必需的。