Java Cloneable没有实现怎么办?

3
我正在从C++转向Java,自认为是Java新手。我最近看了一个庞大的代码库,其中有几个类似于 public class Myclass implements Cloneable{...} 的示例,但没有实现 clone 函数。我不理解这种模式的优势。有吗?如果你选择不实现 clone 函数,为什么要从 Cloneable 派生它?此外,是否有 lombok 注释可以提供一些默认 clone 函数?

Cloneable 是所谓的“标记接口”(marker interface)的一个例子。今天,它可能会使用注解进行标记,但在 Java 中那时并不存在注解。 - Jiri Tousek
Cloneable是一个旧的标记接口。正确而非常简单的答案就是“不要使用它”。没有人使用它。请参见http://www.artima.com/intv/bloch13.html,以获取对此类问题的良好、易于理解的答案,并帮助您进行迁移,请获取并翻阅《Effective Java》。 - pvg
3个回答

1
如果一个类没有实现Cloneable接口,在该类的实例上调用clone方法会导致CloneNotSupportedException异常。 java.lang.Object已经实现了clone方法(此方法不是抽象的),因此子类不需要实现它。 java.lang.Objectclone方法执行实例的浅复制。

1
但是clone方法不是在Object类中被保护了吗?这应该自动防止任何MyClass的使用者调用clone函数。 - cplusplusrat
1
没错,但由于它是受保护的,子类可以在其实现中调用它。如果其他类需要调用它,则可以重写并将其设置为“public”。 - M A
1
好的,那么实现Cloneable接口但不提供实际实现的目的是为了避免子类从基本Object类调用clone函数? - cplusplusrat
实现Cloneable接口的唯一目的是允许克隆实现类的实例。正如文档所说,“按照惯例,实现此接口的类应该使用公共方法覆盖受保护的Object.clone方法”。可能的一种情况是使用反射或其他动态方式调用该方法。 - M A
实现Cloneable没有任何意义。这是一个旧的设计(追溯到Java 1.0),不幸的是它并没有成功,现在已经被认为基本上是有问题的。讨论其操作细节可以获得一些见解,但实际上,重要的是要指出正确的答案是“不要使用Cloneable”。 - pvg

1
如果您选择不实现克隆函数,为什么还要从Cloneable派生它?
clone()方法并不是从Cloneable接口派生而来。而是来自Object类。
Cloneable只是一个标记接口,运行时用于验证对类的实例调用clone()方法的行为。
Java选择了默认情况下,对象拥有clone()方法的设计模式。这是一种你可能喜欢或不喜欢的设计选择,但无论如何,它就是这样的。
具体来说,如果您在对象上调用clone(),并且该对象的类没有实现Clonable,则JVM将在运行时抛出CloneNotSupportedException异常。同样地,有些类会在某个方法未实现时抛出UnsupportedOperationException。
此外,是否有任何lombok注解提供一些默认的克隆函数?
默认情况下,clone() 方法执行的是当前对象的浅拷贝。也就是说,虽然为您克隆了一个新实例,但它所拥有的所有对象字段并没有被克隆。事实上,克隆对象的字段仍然引用原始实例中的相同对象。只有基本类型字段(如 intfloatboolean 等)会被克隆。
如果您需要在 clone() 方法中使用不同的行为,Lombok 无法猜测您希望具有的行为。因此,使用它来生成 clone() 方法的实现是没有意义的。

具体来说,如果您在对象上调用clone()方法,而该对象的类没有实现Clonable接口,则JVM将在运行时抛出CloneNotSupportedException异常,但仅当对象的clone()方法以某种方式使用Object.clone()。如果类以不使用Object.clone()的方式实现了clone(),则无论是否实现了Cloneable接口都没有影响。 - newacct

0

但是你也可以通过向构造函数传递参数来创建一个新对象。这并不会自动为子类创建正确的对象类。 - newacct
注释现在已经过时,被 @With 替代。但是当您使用 With 注释时,在每次 with... 调用之后它会创建新的实例,所以如果您使用普通构造函数,则性能会更好。 - Zhenyria

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