为什么#clone()不在Cloneable接口中?

Phi*_*l K 14 java

我正在阅读正确执行数组的深层副本,但是我对如何#clone()实现它感到困惑.它是java.lang.Object该类的成员,但如果您阅读了javadoc:

首先,如果此对象的类未实现Cloneable接口,则抛出CloneNotSupportedException.

那么为什么要首先定义clone那里的方法呢?当然,如果方法只能在存在接口时使用,则将该方法放在接口中.该Cloneable接口本身是空的; 它只是Java使用的标记接口,以确保使用该clone方法是合法的.

这样做也会消除使用泛型来确保类型安全的能力:

class Foo implements Cloneable { // Valid.
    @Override
    public Object clone() throws CloneNotSupportedException {
        // ...
    }
}

class TypeSafeFoo implements Cloneable<TypeSafeFoo> { // Not valid.
    @Override
    public TypeSafeFoo clone() throws CloneNotSupportedException {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么Java以这种方式完成它?我确信他们有合理的理由,但我似乎无法弄明白.

Mar*_*nik 21

Java中的克隆契约规定每个clone实现必须首先从中获取克隆实例super.clone().这将创建一个始终以调用结束的链Object.clone,并且该方法包含"神奇的"本机级代码,该代码生成struct表示Java对象的基础raw的二进制副本.如果这个机制不存在,clone就不会是多态的:该Object.clone方法产生一个被调用的类的实例; 没有本机代码就无法再现.

这就是为什么Object.clone不能避免这种方法的原因.Cloneable 可能包含一个clone方法,但它会产生有关该throws条款的问题.它的立场是自由声明clone没有声明的异常,或声明任意异常.如果已在接口中声明该方法,则无法实现此灵活性.

请记住,仿制药将是克隆很少使用的:想象protected T clone()Object哪里会:T来自哪里?我们是否需要Object<T>并强制Java Universe中的每个类都要对其自身进行参数化,所有这些只是为了使这个半弃用的机制更好地工作?还要记住,此代码完全合法:

public class TheMightyOne implements Cloneable {
   @Override public TheMightyOne clone() {
     return (TheMightyOne) super.clone();
   }
}
Run Code Online (Sandbox Code Playgroud)

你可以称之为:

TheMightyOne one = new TheMightyOne();
TheMightyOne two = one.clone(); // do downcasts needed
Run Code Online (Sandbox Code Playgroud)


Pat*_*han 6

为了处理创建克隆和基本字段复制,克隆需要继承一个方法实现。Cloneable 类可以出现在层次结构中的任何位置,并且可能需要扩展特定的超类来完成其主要工作。所有可能的 Cloneable 类都可以继承实现的唯一超类是 Object。

克隆的定义早于泛型。