该 clone
方法 Object
,它创建一个对象的精确副本,声明为:
protected native Object clone() throws CloneNotSupportedException;
为什么 native
?
该 clone
方法 Object
,它创建一个对象的精确副本,声明为:
protected native Object clone() throws CloneNotSupportedException;
为什么 native
?
基本上,因为 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
而不是 Object
。 B
不知道一切的实施 A
,因此需要打电话 A
的 clone
方法。但如果 A
实施 clone
用Java语言而不是调用 super.clone()
,然后它将返回的对象必须是 A
。它无法使用 new B()
(假设在创建A时不知道B)。
它可以用反射做一些事情,但它如何知道要调用哪个构造函数以便所有最终字段都能正确填充?
所以诀窍是 A
它本身并没有这样做 super.clone()
,这一直都是回归 Object
,它使用一个本机方法,对原始对象进行逐字节复制,调整新的堆位置。因此,新对象神奇地变成了一个 B
对象和类型转换不会失败。
为什么不回来 Object
然后?因为那不会是克隆。你打电话时 clone
你期望获得两个相同状态(字段)的对象,并且相同 类 (重写和添加方法)。如果它返回了一个内部类名称为的对象 Object
,你只能访问那些东西 Object
提供,如 toString()
,您将无法从另一个访问其私有字段 B
对象,或将其分配给 B
类型变量。
查看克隆文档:
否则,此方法将创建此类的新实例 对象并初始化其所有字段的确切内容 该对象的相应字段,好像是通过赋值;内容 这些田地本身没有克隆。
使用本机代码可以非常有效地完成此操作,因为必须直接复制某些内存。在这方面类似 System.arrayсopy
,这也是原生的。有关详细信息,请参阅此问 是否有可能找到Java本机方法的源代码?
请注意,通常应该避免使用Object.clone(),而是使用复制构造函数,请参阅 如何在Java中复制对象?
它是原生的,因为有些系统类' Clone()
方法是用C ++编写的,以提高性能。