【问题标题】:Why we use cloneable interface in java while making clones of the object?为什么我们在克隆对象时在 java 中使用可克隆接口?
【发布时间】:2022-01-10 14:11:50
【问题描述】:

我是 java 新手,正在研究对象克隆。我的问题是,由于 Object 类是 java 中最顶层的类,所有其他类都继承了这个类,而 clone() 方法是在 Object 类中定义的,那么什么是使用可克隆接口的目的? 为什么我们不能在我们的类中直接重写Object类的clone()方法并从中返回super.clone()(或者根据我们的需求)

还有什么是创建对象克隆的推荐方式(java 标准方式)?使用 clone() 方法或创建复制构造函数,就像 Andreas dolk 对此question 的回答中提到的 C++ 一样?

【问题讨论】:

  • 你可以,但仅仅因为你的类扩展了 Object,并不意味着你自己提供了一个实现。有些流程需要一个 Cloneable 实例,因此,如果您朝着这个方向努力,您可能需要确保您正在实施它
  • Avoid using clone() - 我很确定“Effective Java”也有这方面的一章。也就是说,使用最适合您项目风格的。
  • 谢谢@Stultuske
  • 是的,我发现复制构造函数比通过可克隆接口的克隆方法容易得多。感谢@daniu的建议

标签: java class cloning


【解决方案1】:

clone 的情况是独特的 并且相当反java - 首先不建议使用它是有原因的。 Cloneable 在 JDK 中的使用方式不是你应该注意的——这不是设计 API 的方式,Java 生态系统中没有其他任何东西可以这样工作。

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

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

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

克隆的“系统”是JDK本身提供的,是普通库无法轻易实现的内置功能。有点像“java SomeClass 调用它的主要方法”是 java 本身的一部分。

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

因此,“让所有对象都可克隆”是危险的,因此 java 不想这样做:他们希望您选择加入。 Java 希望类的作者明确地说:是的。我是可克隆的,使用标准机制(如果有记忆,可以深度复制所有字段)。

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

Java 也可以决定做类似的事情:

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

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

@Cloneable
public class Something {}

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

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

【讨论】:

  • 我会采用复制构造方法,因为它具有相同的目的并且比克隆更清晰。此外,您还解释了 Java 上的一些其他平台上没有的东西,并且仅来自经验。感谢您写下这个答案。记好:)
  • 然而,复制构造函数不能使用.clone(),因为任何构造函数都必须“返回”一个新创建的引用,它不能返回从其他东西获得的引用,比如clone()方法。幸运的是,如果您在不使用 clone() 的情况下进行克隆,我推荐使用复制构造函数,例如java.util.ArrayList 和公司。也使用(他们也不在他们的克隆实现中使用clone())。
  • 感谢您提及这一点。
【解决方案2】:

clone() 方法在 Object 中没有实现并且什么都不做。为了让它工作,你的类必须实现 Cloneable。这是一个标记接口,向任何继承它的类添加一些方法,以便您可以克隆该类的对象。

【讨论】:

  • 好的,那么如果Object类和Cloneable接口都没有实现clone()方法,那么return super.clone() works怎么办?
猜你喜欢
  • 1970-01-01
  • 2012-04-21
  • 2012-07-13
  • 2016-06-27
  • 1970-01-01
  • 2015-03-02
  • 1970-01-01
  • 1970-01-01
  • 2011-10-07
相关资源
最近更新 更多