Object
上创建对象精确副本的clone
方法声明为:
protected native Object clone() throws CloneNotSupportedException;
为什么是native
?
答案 0 :(得分:6)
查看克隆文档:
否则,此方法将创建此类的新实例 对象并初始化其所有字段的确切内容 该对象的相应字段,好像通过赋值;内容 这些田地本身并没有被克隆。
使用本机代码可以非常有效地完成此操作,因为必须直接复制某些内存。在这方面类似于System.arrayсopy
,它也是原生的。有关详细信息,请参阅此问题:Is it possible to find the source for a Java native method?
请注意,通常您应该避免使用Object.clone(),而是使用复制构造函数,请参阅How do I copy an object in Java?
答案 1 :(得分:6)
基本上,因为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
在Java语言中实现clone
而不是调用super.clone()
,那么它将返回的对象必须是A
。它不能使用new B()
(假设在创建A时B未知)。
它可以用反射做一些事情,但它如何知道要调用哪个构造函数以便所有最终字段都能正确填充?
所以诀窍是A
自己不做,它调用super.clone()
,这会一直回到Object
,它使用本机方法它会对原始对象进行逐字节复制,并调整新的堆位置。因此,新对象神奇地成为B
对象,类型转换不会失败。
为什么不返回Object
呢?因为那不会是克隆。当您调用clone
时,您希望获得相同状态(字段)和相同类(已覆盖和添加的方法)的对象。如果它返回了内部类标识为Object
的对象,则您只能访问Object
提供的内容,例如toString()
,并且您将无法访问来自另一个B
对象的私有字段,或将其分配给B
类型变量。
答案 2 :(得分:0)
clone()是本机的,因为操作取决于基础平台(也称为OS)。 以下是一些事实,可以帮助您了解实际发生的情况: 1. JVM是用C ++实现的 2. C ++要求您在目标平台/ OS上编译代码 3. clone()操作在内存中进行 4.内存的那部分由JVM(一个C ++程序)控制。 5.将一个类编译为bytecode = text(忽略下面所有冗长的细节,它们仅用于说明) 所以,这:
public static void main(String[] args) {
int a = 1;
int b = 2;
int c = calc(a, b);
}
static int calc(int a, int b) {
return (int) Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
}
成为这个:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
0: iconst_1
1: istore_1
2: iconst_2
3: istore_2
4: iload_1
5: iload_2
6: invokestatic #2 // Method calc:(II)I
9: istore_3
10: return
static int calc(int, int);
descriptor: (II)I
flags: (0x0008) ACC_STATIC
Code:
stack=6, locals=2, args_size=2
0: iload_0
1: i2d
2: ldc2_w #3 // double 2.0d
5: invokestatic #5 // Method java/lang/Math.pow:(DD)D
8: iload_1
9: i2d
10: ldc2_w #3 // double 2.0d
13: invokestatic #5 // Method java/lang/Math.pow:(DD)D
16: dadd
17: invokestatic #6 // Method java/lang/Math.sqrt:(D)D
20: d2i
21: ireturn
我知道这很长,但是很清楚地说明了为什么clone()比“ new”要快-只是将对象的状态捕获为二进制字符串并复制它而没有任何“ thought” /检查。
要了解有关字节码的更多信息,请查看this article in DZone。 请记住.... 计算机科学中的一切都是伪造的,包括类对象,因为它们只是将相关结构和功能组合在一起的另一种抽象,可能是硬件:)除外,大多数人实际上认为属于计算机工程而不是CS。
答案 3 :(得分:-1)
它是原生的,因为某些系统类'Clone()
方法是用C ++编写的,以提高性能。