为什么 Object.clone() 在 Java 中是原生的?
上的 clone
方法创建对象的精确副本,声明为:Object
protected native Object clone() throws CloneNotSupportedException;
为什么会这样?native
上的 clone
方法创建对象的精确副本,声明为:Object
protected native Object clone() throws CloneNotSupportedException;
为什么会这样?native
基本上,因为该方法执行了您在Java语言中无法执行的操作:它克隆了对象的状态,包括其实际的类指定。clone()
Java 中的克隆机制基于调用超类方法的每个类,一直到 。然后,Object 使用这种“神奇”的本机方法来复制原始对象,包括其实际类。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;
}
}
现在假设您有一个类型对象,并且您调用它。您希望获得一个对象,其类在内部被识别为 ,而不是 . 不知道 中所有内容的实现,因此它需要调用 的方法。但是,如果用 Java 语言实现而不是调用 ,那么它将返回的对象必须是 。它不能使用(假设B在创建A时是未知的)。B
clone
B
B
Object
B
A
A
clone
A
clone
super.clone()
A
new B()
它可以对反射做些什么,但是它如何知道要调用哪个构造函数,以便正确填充所有最终字段?
所以诀窍是,它不自己做,它调用,这一直回到,它使用一个本机方法,对原始对象进行逐字节复制,调整新的堆位置。因此,新对象神奇地成为对象,类型转换不会失败。A
super.clone()
Object
B
为什么不返回一个呢?因为那不是克隆。调用时,您希望获得具有相同状态(字段)和相同类(重写和添加的方法)的对象。如果它返回的内部类指定为 的对象,则您只能访问提供的内容,例如 ,并且您无法从另一个对象访问其私有字段,也无法将其分配给类型变量。Object
clone
Object
Object
toString()
B
B
查看克隆文档:
否则,此方法将创建此对象的类的新实例,并使用此对象的相应字段的内容初始化其所有字段,就像通过赋值一样;字段的内容本身不会被克隆。
此操作可以使用本机代码非常有效地完成,因为必须直接复制一些内存。它在这方面是相似的,它也是原生的。有关详细信息,请参阅以下问题:是否可以找到 Java 本机方法的源代码?System.arrayсopy
请注意,通常您应该避免使用 Object.clone(),而使用例如复制构造函数,请参阅如何在 Java 中复制对象?