当前位置: 首页 > 面试题库 >

Java:super.clone()方法和继承

聂华翰
2023-03-14
问题内容

我有一个关于clone()Java中用于super.clone()继承的方法的快速问题-在哪里我clone()从按钮一直到父类中调用该方法。

clone()方法应该返回该对象的副本,但是如果我在继承继承中有三个类并调用super.clone()三次,为什么继承继承中的最高类(仅在Object类下)获取该类的副本回来?

假设我们有三个类:A,B和C,其中A-> B-> C(继承=->)

然后,super.clone()在类C中进行调用,clone()在B中进行调用super.clone(),在B中进行调用,clone()在A中进行调用,这将调用super.clone()“这次Object.clone()被调用”。为什么返回的不是this关于类A
的对象的副本Object.clone()?这对我来说听起来很合逻辑。


问题答案:

听起来这里至少有两个问题在起作用:

  1. 听起来您对clone()的正常实现方式感到困惑。

  2. 听起来您好像在想克隆是个好主意(与使用复制构造函数,工厂或其等效对象相比)。

这是克隆方法的实现示例

@Override 
public Object clone() throws CloneNotSupportedException {   
    //get initial bit-by-bit copy, which handles all immutable fields
    Fruit result = (Fruit)super.clone();

    //mutable fields need to be made independent of this object, for reasons
    //similar to those for defensive copies - to prevent unwanted access to
    //this object's internal state
    result.fBestBeforeDate = new Date( this.fBestBeforeDate.getTime() );

    return result;
}

请注意,的结果将super.clone()立即转换为Fruit。这样,继承方法便可以修改特定于Fruit的成员数据(fBestBeforeDate在这种情况下)。

因此,对子clone()方法的调用虽然将调用父级的克隆,但也会对新制作的副本添加其自身的特定修改。在这种情况下,结果将是Fruit,而不是Object

现在,更重要的是, 克隆是一个坏主意 。复制构造函数和工厂提供了更为直观和易于维护的替代方案。尝试阅读我附加到示例的Java
Practices
链接上的标题:该标题总结了一些问题。乔什·布洛赫(Josh
Bloch)的讨论时间也更长:绝对应该避免克隆。这是一段很棒的摘要段落,说明了他为什么认为克隆是一个问题:

对象的克隆方法非常棘手。它基于字段副本,并且是“额外语言”。它创建一个对象而不调用构造函数。无法保证它保留了构造函数建立的不变式。多年来,在Sun内部和外部都有许多错误,这是由于以下事实造成的:如果您仅调用super.clone,直到在克隆对象之前,都在链中反复调用,则该对象会有一个浅表副本。克隆通常与要克隆的对象共享状态。如果该状态是可变的,则您没有两个独立的对象。如果您修改其中一个,则其他也将更改。突然之间,您会得到随机的行为。



 类似资料:
  • 因此,我理解在实现方法时,应该首先调用,这样(潜在的)超类就可以完成它的工作,然后进行自己的克隆。这一切都确保超类中的非变量是列表/非克隆的。 现在,如果我使用Jacksons ObjectMapper进行克隆: 我决定这样做,因为我的对象()已经完全可以与json进行转换,json基本上就是在克隆。 在这种情况下调用super.clone()是没有用的,对吧?Jackson无论如何都会在以这种方

  • 问题内容: 我的课是: 我在这个类中写一个子类: 注意在 覆盖类中 的 getX 方法时,我已经从方法定义中删除了该子句,现在它导致编译器出现异常行为,这是预期的: 不会如预期那样将其封闭在一个块中而无法编译。 编译而不将它封闭在一个块中。 但是下面的代码行需要try-catch块。 就像可以预见的那样,即在运行时多态期间使用父类引用来调用子方法,为什么Java的设计人员在覆盖特定的父类方法时没有

  • 本文向大家介绍C#继承方法,包括了C#继承方法的使用技巧和注意事项,需要的朋友参考一下 示例 有几种方法可以继承            

  • 问题内容: 这是我遇到的一个测试练习问题,希望您能帮助我理解概念 让Hawk成为Bird的子类。假设某个类有两个重载的方法void foo(Hawk h)和void foo(Bird b)。在声明Bird x = new Hawk()之后,将在调用foo(x)中执行哪个版本; 这是我到目前为止的代码,有人可以向我解释为什么foo(bird b)被执行吗? 问题答案: Java执行重载解析以选择方法

  • 问题内容: 我是python的初学者。我无法理解继承和。 结果: 还行吧。但我替换为 结果: 在这种情况下,如何访问? 问题答案: 在第一种情况下,是扩展类,并且由于您没有重新定义in中命名的特殊方法,因此它继承自。 当类定义 方法时,类实例化将自动为新创建的类实例调用。 在第二种情况下,由于要重新定义,因此如果要扩展其行为,则需要在超类()中显式调用它。

  • 问题内容: 我有一个具有通用方法的抽象类,并且我想通过用特定类型代替通用参数来覆盖通用方法。所以在伪代码中,我有以下内容: 但是由于某种原因,我不允许这样做?我是在犯某种语法错误还是不允许这种继承和覆盖?具体来说,由于eclipse IDE不断提醒我要实现,我遇到了一个错误。 这就是我希望上面的代码起作用的方式。在我的代码的其他地方,有一个方法可以期望实现对象的实例,这具体意味着它们具有我可以使用