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

问题描述

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

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

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

并继续推理

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

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

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

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

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

解决方法

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()无论如何都期待着?

猜你在找的技术问答相关文章

如何检查配对的蓝牙设备是打印机还是扫描仪(Android)
是否允许实体正文进行HTTP DELETE请求?
如何将ZipInputStream转换为InputStream?
java.util.logging Java 8中的变量
PowerMockito.doReturn返回null
Java中的RESTful调用
Swing / Java:如何正确使用getText和setText字符串
特殊字符和重音字符
Android Studio中的ndk.dir错误
错误“找不到主类”