Cloneable#clone 方法不必要的强制转换

Con*_*hai 2 java java-8

class MyCls implements Cloneable {
  @Override
  protected MyCls clone() throws CloneNotSupportedException {
    return new MyCls(//...
  }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码没有任何问题。那么为什么CopyOnWriteArrayList#clone返回一个Object而不是CopyOnWriteArrayList?从转换回Object所需类型时,编译器会哭。毕竟,这个设计决定的原因是什么?我看到整个图书馆都在重复这种模式。

Ralph建议下面的代码是有效的,而不是上面的代码:

@Override MyCls clone() throws CloneNotSupportedException { 
  MyCls clone = (MyCls)super.clone();
  clone.x = this.x; //or what ever to do return clone
  // ...
}
Run Code Online (Sandbox Code Playgroud)

问题还是一样。为什么CopyOnWriteArrayList#clone返回Object而不是它自己?

Hol*_*ger 6

您的问题基于协变返回类型,即使用更具体的返回类型覆盖方法的能力。

这个特性在 Java 中并不总是存在。更准确地说,它是在 Java 5 中引入的,该版本还引入了并发工具,包括CopyOnWriteArrayList.

但这并不是说先开发语言更新,然后再开发类。这些课程经历了在 Java 5 和更早版本之前开始的开发过程,草稿可以从http://gee.cs.oswego.edu/dl/concurrency-interest/下载

因此,早期版本必须声明与覆盖方法相同的返回类型,当它们与 Java 5 一起发布时,没有人及时考虑更改方法以使用协变返回类型。显然仍然没有人负责考虑它。它可能不够重要。

这不是一个独特的情况。

NIO BufferAPI 是在 JDK 1.4 中引入的,这是协变返回类型可能之前的一个版本,直到 Java 9,才添加了具有更具体返回类型的覆盖(例如ByteBuffer.position(int), limit(int), or clear(); 与仅继承版本的 Java 8版本相比,阻碍了 API 的流畅使用)。

但是请注意,在类发布后更改方法以使用协变返回类型,当您在比预期运行的 JDK 版本更新的情况下编译代码时,可能会产生兼容性问题。该解决方案--release选项,也被介绍为晚9 JDK。