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


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

protected native Object clone() throws CloneNotSupportedException;

为什么 native


5831
2017-12-01 08:46


起源

请解开你的问题。 - Maroun
相关(重复?): stackoverflow.com/a/557606/1225328 - sp00m
@ sp00m,谢谢。 - Aamir
这个问题对于原因并没有真正的结论性答案 克隆 是原生的,只是某人的猜测。 - Chris Martin
同意。我被提名重新开放。 “什么是”之间存在巨大差异 native“和”为什么声明这个方法 native“? - Chris Hayes


答案:


基本上,因为 clone() 方法做了一些你不能用Java语言做的事情:它克隆了对象的状态,包括它的实际类名。

Java中的克隆机制基于调用超类的每个类 clone 方法,一直到 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;

    }
}

现在想象你有一个 B 键入对象,然后调用 clone 在上面。你希望得到一个 B 对象,其类在内部被识别为 B而不是 ObjectB 不知道一切的实施 A,因此需要打电话 Aclone 方法。但如果 A 实施 clone 用Java语言而不是调用 super.clone(),然后它将返回的对象必须是 A。它无法使用 new B() (假设在创建A时不知道B)。

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

所以诀窍是 A 它本身并没有这样做 super.clone(),这一直都是回归 Object,它使用一个本机方法,对原始对象进行逐字节复制,调整新的堆位置。因此,新对象神奇地变成了一个 B 对象和类型转换不会失败。

为什么不回来 Object 然后?因为那不会是克隆。你打电话时 clone 你期望获得两个相同状态(字段)的对象,并且相同  (重写和添加方法)。如果它返回了一个内部类名称为的对象 Object,你只能访问那些东西 Object 提供,如 toString(),您将无法从另一个访问其私有字段 B 对象,或将其分配给 B 类型变量。


6
2017-12-01 10:05



Object.clone执行浅拷贝,而不是深拷贝 - lbalazscs
@Ibalazscs为true,但在用户类中的实现通常必须自己进行深度复制。这就是为什么他们通常需要覆盖它而不仅仅是保持原样。 - RealSkeptic


查看克隆文档:

否则,此方法将创建此类的新实例   对象并初始化其所有字段的确切内容   该对象的相应字段,好像是通过赋值;内容   这些田地本身没有克隆。

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

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


6
2017-12-01 09:50





它是原生的,因为有些系统类' Clone() 方法是用C ++编写的,以提高性能。


-2
2017-12-01 08:49



这是如何回答这个问题的? - Maroun
这是抛出异常的原因 - Adem
再次阅读问题。 - Maroun
好。我想我应该阅读所有不断变化的问题,我应该根据当前的问题改变我的答案。顺便说一句,这是原始问题的答案 - Adem
这里有一些混乱。最初的问题是措词不清(现在仍然如此),这个答案,在其第一个版本中,实际上除了这一点。我相信情况不再如此。实际上,这个答案远没有那么好,但请停止抨击。 - RandomSeed