为什么我们在克隆对象时使用 java 中的可克隆接口?

Why we use cloneable interface in java while making clones of the object?

我是 java 的新手,正在研究对象克隆。我的问题是,因为 Object class 是 java 中最顶层的 class 并且所有其他 classes 继承了这个 class 和 clone() 方法定义在 Object class,那么使用 cloneable 接口的目的是什么? 为什么我们不能在 class 和 return [=26] 中覆盖 Object class 的 clone() 方法=]() from it(或者根据需要修改为深拷贝)?

另外,创建对象克隆的推荐方式(java 标准方式)是什么?使用 clone() 方法或像 C++ 一样创建复制构造函数,这在 Andreas dolk 对此 question?

的回答中有所提及

clone() 方法在 Object 中没有实现并且什么也不做。要使其工作,您的 class 必须实施 Cloneable。这是一个标记接口,并向继承它的任何 class 添加一些方法,以便您可以克隆该 class.

的对象

clone 情况是 独特的 并且相当反 java-like - 首先不建议使用它是有原因的.在 JDK 中使用 Cloneable 的方式不是你应该记下的东西——这不是设计 API 的方式,在 java 生态系统中没有别的这样工作。

奇怪的是,这很常见:java 的核心部分通常与 java 不同。例如,任何头脑正常的人都不会创建一个 API 来定义一个应用程序,“它有一个带有签名 public static void main(String[] args) 的方法”。显而易见的设计原则是制作一个抽象 class 或带有抽象 start() 方法的接口,并制作一个 java 应用程序,你编写一个 class 没有- args 构造函数和 implements/extends 即 interface/class。数组也是如此:它们很奇怪——至少可以说,它们的 toString、equals 和 hashCode 实现令人惊讶。它们也不完全是类型安全的。

所有这一切的原因都是历史性的:要解释它们,您需要了解当时相关的各种事情,但这些事情已经不重要了,而且已经有几十年了。

Cloneable 也不例外。让我解释一下为什么会这样:

克隆的'system'是由JDK本身提供的,它是一个普通图书馆无法轻易制作的内置东西。有点像“java SomeClass 调用它的主要方法”是 java 本身的一部分。

但是,系统需要一个选择加入机制:克隆行为可能没有意义('clone' 代表 TCP 网络连接的传入字节的 InputStream 意味着什么? 'clone' 试图保证只有一个实例存在的枚举的值是什么意思?'clone' 单身人士是什么意思?)

因此,'just make all objects cloneable'危险,所以java不想这样做:他们希望你选择加入 就可以了。 Java 希望 class 的作者明确地说:是的。我是可克隆的,使用标准机制(深度复制所有字段,如果有记忆的话)。

这就是 Cloneable 的用途! - 这就是 你说的:是的。我很好。通过实施。这是一面旗帜。

Java 也可以决定做如下事情:

/** @cloneable */
public class Something {}

相反,但他们没有。如果它是在这个更现代的时代设计的,也许它看起来像:

@Cloneable
public class Something {}

但是在 java 1.5 中引入注释作为 1.6 中的演示功能是正确的。可克隆界面与 java 1.0 一样古老——十多年前。 “添加一个什么都不定义的接口”是当时标记 class 属性的标准方法,即使现在不是。

注意:您不 只是 implements Cloneable,您还创建了一个 public 克隆方法。 implements Cloneable 部分告诉克隆系统:你可以克隆这个 class,例如,即使它是被克隆的包含对象的深层结构的一部分。创建一个调用 j.l.Object 具有的受保护的 JVM 提供的 clone() 方法的克隆方法就是公开 API 的方式。也许您想将其命名为 copy,或者您可能想要克隆但不作为 public API 的一部分。你的问题不是关于如何使用克隆,而是它为什么像现在这样工作——如果你想使用它,我的建议很简单。不要,自己编写克隆代码,或者更好的是,设计具有更多不可变项的 API,这样就不再需要克隆了。