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

为什么在Java 8中Cloneable中没有默认的clone()

俞新翰
2023-03-14
问题内容

CloneableJava固有地被破坏了。具体来说,我与接口有关的最大问题是,它期望方法行为无法定义方法本身。因此,如果遍历Cloneable列表,则必须使用反射来访问其定义的行为。但是,在Java
8中,我们现在有了默认方法,现在我问为什么在中没有默认clone()方法Cloneable

我知道为什么接口不能使用默认的Object方法,但是,这是一个明确的设计决定,因此可以进行例外处理。

我有点设想过时Object.clone(),并将其内部代码更改为以下内容:

if(this instanceof Cloneable) {
    return ((Cloneable) this).clone();
}
else {
    throw new CloneNotSupportedException();
}

并且继续进行任何魔术创造clone()的事情,作为中的默认方法Cloneable。这并不能解决clone()仍然可以很容易地错误实现的问题,但这本身就是另外一个讨论。

据我所知,此更改将完全向后兼容:

  1. 当前覆盖clone()但未实现的类Cloneable(为什么?!)在技术上还是可以的(即使在功能上是不可能的,但这和以前没什么不同)。
  2. 当前覆盖clone(),但是实现Cloneable了的类在其实现上仍将发挥相同的作用。
  3. 当前未覆盖clone(),但实现了Cloneable(WHY ?!)的类现在将遵循规范,即使它在功能上并不 完全 正确。
  4. 使用反射并引用的那些在Object.clone()功能上仍将起作用。
  5. super.clone()即使在引用时,在功能上仍然相同Object.clone()

更不用说这将解决一个巨大的问题Cloneable。尽管繁琐并且仍然容易错误地实现,但是它将通过接口解决一个巨大的面向对象的问题。

我能看到的唯一问题是那些实现Cloneable者没有义务重写clone(),但这与以前没有什么不同。

是否在内部进行过讨论,但从未实现过?如果是这样,为什么?如果是由于接口无法默认Object方法的原因,那么在这种情况下将异常设置为有意义,因为所有继承Cloneable的对象clone()无论如何都期待着?


问题答案:

您的问题有些广泛,需要更多讨论,但我可以就此问题提供一些启示。

在《 有效的Java™》中 ,Joshua Bloch给出了有关情况的简要说明。他的开场白有着悠久的历史Cloneable

Cloneable接口旨在用作对象的混合接口,以宣告它们允许克隆。不幸的是,它不能达到这个目的。它的主要缺陷是缺少克隆方法,并且对象的克隆方法受到保护。如果不依靠反射,就不能仅仅因为对象实现Cloneable而在对象上调用clone方法。

并继续推理

[Cloneable]决定对象受保护的克隆实现的行为:如果一个类实现了Cloneable,则对象的clone方法将返回该对象的逐字段副本…这是一种非常不典型的接口使用方式,而不是被仿真的接口。通常,实现接口会说明类可以为其客户端执行的操作。在Cloneable的情况下,它会修改超类上受保护方法的行为。

如果实现Cloneable接口对一个类有任何影响,则该类及其所有超类必须服从一个相当复杂,不可执行且内容简短的协议。由此产生的机制是语言外的:它无需调用构造函数即可创建对象。

这涉及很多细节,但仅需注意一个问题:

克隆体系结构与引用可变对象的final字段的正常使用不兼容。

我认为这足以阻止default在接口中进行克隆。正确实现它将极其复杂。



 类似资料:
  • Java中的本质上是不可靠的。具体地说,我对接口的最大问题是,它需要一个不定义方法本身的方法行为。因此,如果遍历一个列表,您必须使用反射来访问它定义的行为。然而,在Java8中,我们现在有了默认方法,现在我问为什么在中没有默认的方法。 我理解为什么接口不能默认对象方法,但是,这是一个明确的设计决定,所以可以做出例外。 我有点想弃用并将其内部代码更改为类似以下内容: 然后继续使用使作为中的默认方法的

  • 我试图理解object.clone()在Java中是如何工作的。我偶然发现了以下事实: null 疑点: 为什么Java设计者会做出这样的设计选择并这样实现它?为什么不在本身中定义,如果实现类不为提供实现,那么将产生编译时错误。 Q2.为什么要在运行时检查实例是否实现? 附:我知道在一个问题中问多个问题是一个坏主意。但这些都是密切相关的问题。我可以问一个问题,比如“为什么不包含?”但是,我觉得,为

  • 问题内容: 我正在阅读有关如何正确执行数组深拷贝的信息,但是我对如何实现数组感到困惑。它是该类的成员,但是,如果您阅读javadocs: 首先,如果此对象的类未实现Cloneable接口,则将引发CloneNotSupportedException。 那么为什么要首先定义方法呢?当然,如果仅当存在接口时才可以使用方法,则可以将方法放在接口中。该接口本身是空的; 它只是Java用来确保使用该方法合法

  • 我正在阅读如何正确执行数组的深度复制,但是我对是如何实现的感到困惑。它是类的成员,但是如果您阅读Javadocs: 首先,如果该对象的类没有实现接口Cloneable,则抛出CloneNotSupportedException。 为什么Java要这样做?我肯定他们有正当的理由,但我似乎想不通。

  • 我从这里下载MySQL ZIP Archive:https://dev.mysql.com/downloads/mysql/(Windows(x86,64位), ZIP Archive) 我从来没有使用zip文件安装。所以我遵循这个教程:https://www.youtube.com/watch?v=kJbwKQqwtoE 从youtube教程中,解压缩zip文件后,会出现 但是当我提取zip文件

  • 问题内容: 默认方法是Java工具箱中一个不错的新工具。但是,我试图编写一个定义方法版本的接口。Java告诉我,这是禁止的,因为in中声明的方法可能无法编辑。为什么会这样呢? 我知道有一个“基类始终获胜”规则,因此默认情况下(pun;),方法的任何实现都会被该方法覆盖。但是,我认为没有理由为什么规范中的方法不应有例外。特别是因为它具有默认实现可能非常有用。 那么,Java设计者决定不允许方法覆盖方