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

Aam*_*mir 13 java clone native object

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

protected native Object clone() throws CloneNotSupportedException;
Run Code Online (Sandbox Code Playgroud)

为什么native

Rea*_*tic 9

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

Java中的克隆机制基于每个类调用超类的clone方法,一直到最后Object.然后,Object使用这个"神奇"的本机clone方法来复制原始对象,包括它的实际类.

想一想:

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;

    }
}
Run Code Online (Sandbox Code Playgroud)

现在假设你有一个B类型对象,并调用clone它.你希望得到一个B对象,其内部被认为是B,而不是Object.B不知道在一切的实现A,因此它需要调用Aclone方法.但是,如果A实施clone在Java语言中,而不是调用super.clone(),那么它将返回的对象必须是A.它不能使用new B()(假设在创建A时B未知).

它可以用反射做一些事情,但它如何知道要调用哪个构造函数以便所有最终字段都能正确填充?

所以诀窍是A不会自己动手,它会调用super.clone(),并且这一直都会回来Object,并且它使用一个本机方法,对原始对象进行逐字节复制,调整新的堆位置.因此,新对象神奇地成为一个B对象,类型转换不会失败.

为什么不回来Object呢?因为那不会是克隆.当你打电话时,clone你希望得到一个相同状态(字段)和同一个(被覆盖和添加的方法)的对象.如果它返回了一个内部类名称为的对象,则Object只能访问Object提供的内容,例如toString(),您将无法从另一个B对象访问其私有字段,或将其分配给B类型变量.


lba*_*scs 6

查看克隆文档:

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

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

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