为什么Java中的类默认情况下不能被克隆?

7

在Java中,要使一个类可克隆,我们需要实现Cloneable接口。实现此接口只是表明该类支持克隆。

但是,Java语言设计者之所以没有将“允许克隆”作为每个类的默认功能,是出于什么动机呢?

我们已经有浅复制的默认实现了。那么为什么还要有这种限制呢?

4个回答

5

想象一下克隆一个具有嵌套属性的对象。你希望递归多深?这可能会对内存造成压力,所以开发人员将其留给我们来决定。


1
默认实现创建了浅拷贝,因此开发人员不需要考虑“多深”的问题。问题在于,如果语言提供了浅拷贝的默认机制,为什么不允许直接使用呢?为什么要额外添加一个 Clonable 步骤呢? - Kaushik Lele
想象一下在具有对object2的引用的对象上使用clone()。现在您调用copy.getObject2().setX(x)。您已经为它们两个更改了object2(因为它仍然是默认浅复制中的引用)。这意味着clone()是一个危险的方法,因此最好将其标记为另一行错误防御。 - eugen-fried

4
这是一个标记接口,用于告诉Java实现类“有意设计为可克隆”(与其他标记接口的使用方式类似)。如果您继续阅读,您将发现以下内容:
按照惯例,实现此接口的类应该重写Object.clone(受保护)方法,并提供一个公共方法。有关重写此方法的详细信息,请参见Object.clone()。
您需要提供自定义的克隆方法。通过使用接口Cloneable,Java知道您有意支持对象的克隆。通过提供自定义的克隆方法,您覆盖了对象的默认克隆方法。
这样,您就可以灵活地决定哪些对象可以被克隆,哪些不行。如果可克隆,则可以达到什么级别(在对象图案例中非常有用)。

问题是,如果语言提供了浅拷贝的默认机制,那为什么不允许直接使用它呢?为什么要额外实现Clonable接口呢? - Kaushik Lele
@KaushikLele 这就是我试图解释的内容。浅拷贝是一种轻量级的过程,您不需要在内存中创建所有新对象(您可以重用内存引用)。在这里,您正在创建新对象。在这种情况下,该接口提供了一种机制,您可以决定要复制什么和什么不复制。当您处理长对象图(嵌套对象)时,这非常有用。 - Yogendra Singh

0

有许多原因阻碍了克隆的实现,其中最主要的原因是克隆不像序列化一样可以解决通用问题。

默认情况下得到的浅拷贝在许多情况下会破坏对象的不变性,因此它不能作为一种通用的默认克隆机制。


问题是,如果编程语言提供了浅拷贝的默认机制,为什么不允许直接使用它呢?为什么要额外实现Clonable接口? - Kaushik Lele
正如我所说,因为这会强制将此方法应用于每个Java对象的契约,并且默认的浅拷贝会破坏大多数Java类的不变式。这意味着该类将被迫不情愿地实现。有些对象甚至在理论上都无法克隆。请花一点时间考虑Singleton模式。 - Marko Topolnik

0

"Cloneable" 接口是设计模式中的一种 "标记类"。基本上,在克隆方法中将会有一些引用到类型 "Cloneable"。当您实现 Cloneable 接口时,意味着您的类可以被引用为类型 "Cloneable"。

另一个实际的原因是,您可以重写 "clone()" 方法,并以自己特定的方式进行克隆。这意味着您认为重要的数据存在于新类中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接