为什么 Object.clone() 在 Java 中是原生的?

2022-09-03 06:29:39

上的 clone 方法创建对象的精确副本,声明为:Object

protected native Object clone() throws CloneNotSupportedException;

为什么会这样?native


答案 1

基本上,因为该方法执行了您在Java语言中无法执行的操作:它克隆了对象的状态,包括其实际的类指定。clone()

Java 中的克隆机制基于调用超类方法的每个类,一直到 。然后,Object 使用这种“神奇”的本机方法来复制原始对象,包括其实际类。cloneObjectclone

想想这个:

class A implements Cloneable {

    public A clone() {

        A obj = (A) super.clone();

        // Do some deep-copying of fields

        return obj;
    }

}

class B extends A {

    public B clone() {

        B obj = (B) super.clone();

        // Do some deep-copying of fields not known to A

        return obj;

    }
}

现在假设您有一个类型对象,并且您调用它。您希望获得一个对象,其类在内部被识别为 ,而不是 . 不知道 中所有内容的实现,因此它需要调用 的方法。但是,如果用 Java 语言实现而不是调用 ,那么它将返回的对象必须是 。它不能使用(假设B在创建A时是未知的)。BcloneBBObjectBAAcloneAclonesuper.clone()Anew B()

它可以对反射做些什么,但是它如何知道要调用哪个构造函数,以便正确填充所有最终字段?

所以诀窍是,它不自己做,它调用,这一直回到,它使用一个本机方法,对原始对象进行逐字节复制,调整新的堆位置。因此,新对象神奇地成为对象,类型转换不会失败。Asuper.clone()ObjectB

为什么不返回一个呢?因为那不是克隆。调用时,您希望获得具有相同状态(字段)和相同(重写和添加的方法)的对象。如果它返回的内部类指定为 的对象,则您只能访问提供的内容,例如 ,并且您无法从另一个对象访问其私有字段,也无法将其分配给类型变量。ObjectcloneObjectObjecttoString()BB


答案 2

查看克隆文档:

否则,此方法将创建此对象的类的新实例,并使用此对象的相应字段的内容初始化其所有字段,就像通过赋值一样;字段的内容本身不会被克隆。

此操作可以使用本机代码非常有效地完成,因为必须直接复制一些内存。它在这方面是相似的,它也是原生的。有关详细信息,请参阅以下问题:是否可以找到 Java 本机方法的源代码?System.arrayсopy

请注意,通常您应该避免使用 Object.clone(),而使用例如复制构造函数,请参阅如何在 Java 中复制对象?