4

考虑 The Java Programming Language 书中的以下代码

public class MyClass extends HerClass implements Cloneable {
   public MyClass clone()
       throws CloneNotSupportedException {
       return (MyClass) super.clone();
   }
   // ...
}

当覆盖的 clone() 函数已经将返回类型指定为 MyClass 时,在 return 语句中再次指定它的要求是什么?另外,由于正在创建 Myclass 的超类对象的克隆(因为 clone() 被称为 wrt 超类),它怎么可能是 Myclass 类型的?

提前致谢

4

4 回答 4

1

理论上你是对的:因为你必须指定函数返回值的类型,编译器可以尝试自动执行更正。另一方面,需要显式转换有助于识别可能的错误。

除非您有特定要求,否则类的clone()方法Object已经做了正确的事情,即它创建了正确类的对象并复制克隆对象中的所有非静态属性。但是,它不能将其作为派生类型返回,因为在编译时该类型对于Object类本身来说是未知的。

确实clone()可以为所有类自动提供该方法,但有时您不希望它可用,而在其他时候您想覆盖默认行为;例如,您的类中可能有一个id属性,即使在克隆时,您也希望类的每个实例都不同。必须重写该clone()方法为您提供了一个可以实现此类功能的地方。

于 2011-08-28T17:39:26.690 回答
1

这是因为Objectclone()中的方法返回一个. 但是,您可以在 clone() 中返回您的子类,因为它扩展了一个对象。如果方法看起来像这样ObjectMyClass

public Object clone()

那么它仍然是一个有效的可克隆对象并且它会工作。你不需要投射任何东西。该接口Cloneable只是一个标记接口,这意味着它实际上没有任何方法。

于 2011-08-28T17:41:21.557 回答
1

首先是您的简单问题:为什么要super.clone()转换为MyClass?那是因为声明HerClass.clone()指定了一个返回值HerClass,所以你必须将它转换为正确的类型。

现在,对于更困难的问题:如何super.clone()实际返回MyClass? 实际上我很难找到答案,但我确实在 Joshua Bloch 的 Effective Java 中找到了答案。Object.clone()在我不太明白的背景中仍然有一些“魔法” 。

书中第11条:

实际上,程序员假设如果他们扩展一个类并从子类调用 super.clone,则返回的对象将是子类的一个实例。超类可以提供此功能的唯一方法是返回通过调用 super.clone 获得的对象。如果一个克隆方法返回一个由构造函数创建的对象,那么它将具有错误的类。因此,如果您在非最终类中重写 clone 方法,您应该返回一个通过调用 super.clone 获得的对象。如果一个类的所有超类都遵守这个规则,那么调用 super.clone 最终会调用 Object 的 clone 方法,创建一个正确类的实例。

我最初试图通过编写程序来回答您的问题,但并不知道您总是必须调用super.clone(). 我自制的克隆方法是返回一个从构造函数()生成HerClass的新实例。代码已编译,但在我尝试强制转换时执行失败。只有被链接的方法才能返回一个值,该值是其子类型之一的实例。HerClassnew HerClass()(MyClass) super.clone()Object.clone()

请注意,如果HerClass.clone()没有显式实现,默认情况下它只是返回Object.clone(). 默认方法具有protected访问权限,但由于您是从子类调用它,所以这不是问题。

于 2011-08-28T19:01:33.157 回答
1

因为clone()返回一个 Object 类的对象,你必须将它转换为正确的类型。但是您知道它是 MyClass 类型的对象,因此强制转换是正确的。

于 2011-08-28T17:17:26.923 回答