【问题标题】:Behaviour towards object cloning in JavaJava中对象克隆的行为
【发布时间】:2015-09-17 13:23:34
【问题描述】:

我正在学习 Java,因为我需要它作为我的一门大学课程的先决条件。 我来自 C++ 背景,所以理解 OOP 底层的逻辑并不是特别困难。 但这两种语言之间存在一些差异,其中一个我无法弄清楚的是 Java 中存在的对象克隆功能。 这个问题让我想起了 C++ 的复制构造函数,但含义不同。

在 Java 中,没有析构函数,内存由垃圾收集器管理,因此不存在您在 C++ 中遇到的堆内存问题。问题仅限于共享变量。

现在,仔细阅读,我发现对象克隆(与复制构造函数不同)不是 OOP 语言应该提供的功能,因为它创建了另一个跳过构造阶段的对象实例。此外,clone() 无法正确操作 final 字段,并跳过初始化块。克隆背后的相同逻辑是“错误的”,因为“Cloneable”就像一个空接口,仅用于在 Object.clone() 中进行类型检查,以在对象类型不可克隆时引发异常。

所有的克隆机制似乎都依赖于正确分配内存的 Object.clone() 方法。支持 clone() 的类层次结构中的每个子类型都应该调用“super.clone()”,直到调用 Object 来分配所有必要的字段。 但是,如果实现 Cloneable 接口的子类型扩展了不这样做的超类型,会发生什么? 我正在学习“Arnold,Gosling,Holmes”,对克隆的定义行为之一是:“允许子类支持克隆但不公开支持它。这样的类不实现 Cloneable,但如果默认克隆的实现不正确,该类提供了一个受保护的克隆实现,可以正确克隆其字段”。 这样调用super.clone(),最后会碰到超类的受保护的clone()方法,但是这样的方法不能依赖Object.clone(),因为超类本身没有实现Cloneable。使用 new 运算符会出错,因为会创建一个超类的实例,其中缺少一些字段。

那么,在非 Cloneable 类中支持 clone()(使用受保护的方法)真的有用吗? 以及如何解决具有不可克隆超类型的可克隆子类型的问题?

【问题讨论】:

  • Cloneable / clone() 是一个完全被破坏的机制。我建议你避免它。阅读有效的 Java 第 11 条:明智地覆盖克隆。或阅读:artima.com/intv/bloch13.html
  • 一些 OOP 课程将教您如何正确实现克隆(使用复制构造函数),并要求您在数据类中这样做。然而,在实践中,支持克隆要么不是太有用,要么不是明智的选择。你可以这样做,但你应该事先考虑是否值得。
  • 另外,可能相关:stackoverflow.com/questions/2326758/…

标签: java


【解决方案1】:

但是,如果实现Cloneable 接口的子类型扩展了不这样做的超类型,会发生什么?

如果它只是 implements Cloneable 而没有实际覆盖 clone()(是的,这也是可能的!),那么不会造成任何伤害。

如果它覆盖clone() 并返回一个不是从super.clone() 检索到的实例,那么它已经破坏了它的所有子类。这是clone() 公认的缺陷之一(在 Effective Java 中有介绍)。

如何解决具有不可克隆超类型的可克隆子类型的问题?

如上所述,只要不可克隆的超类型不覆盖clone()(是的,这是另一种可能性!)或确实覆盖它,这不是问题,但在合规的方式。

【讨论】:

  • 所以,即使超类型没有实现Cloneable,如果子类型的clone()方法调用super.clone(),实际上调用的是Object.clone()。但是你不能不得到超类字段的浅拷贝
  • 您的意思肯定是“深拷贝”。不,您无法理解,但至少这不是 Cloneable 的特定问题。
【解决方案2】:

如何解决 Cloneable 子类型与不可 Cloneable 超类型的问题?

其实这不是问题。想想Object 类:这是一个不可克隆类型,用作任何Cloneable 类型的超类型。您可以创建任何类型 T 的 Cloneable 子类型。唯一重要的是:为该类型 T(及其超类型)正确实现了“克隆”操作。对于Object 类,这将返回原始对象的字段级浅拷贝,与原始对象具有相同的类。

即并非子类的超类线程中的每个类型都必须实现Cloneable。

... 在非 Cloneable 类中支持 clone()(带有受保护的方法)真的有用吗?

是的。例如。参见(不可克隆)类Object中clone()的默认实现。

【讨论】:

  • 我明白你的意思。但这让我很困惑:如果超类型没有实现 Cloneable 而是提供了受保护的 clone() 方法,如果子类型调用 super.clone(),则会调用超类的受保护方法。因此,副本将被破坏,因为超类型无法调用 Object.clone()
  • 我进行了一些测试。如果你的超类型没有实现 Cloneable,但是你提供了一个使用 super.clone() 的受保护的 clone() 方法,它可以访问 Object.clone(),只要子类型调用 super.clone()(在它被覆盖的克隆内部) () 方法)实现 Cloneable。其实Object.clone()执行的类型检查,就是在this上进行的,它指向一个子类型的Cloneable对象
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-07
  • 1970-01-01
  • 2017-02-23
  • 1970-01-01
相关资源
最近更新 更多