clone() 是原生的,因为操作依赖于底层平台,也就是操作系统。
以下是一些有助于掌握实际情况的事实:
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 SomeClassname() 那样进行分析 - 找出类在内存中的位置,构造函数在哪里,然后找出变量类型,传递初始化值(如果有),并执行分配(如果有)。你明白了。
- 由于对给定类型的特定对象调用 clone(),因此类型本身是已知的,不需要上面 (8) 中的分析。甚至实例变量的值都是一样的,所以我们不需要传递任何东西。
- 剩下的唯一问题是 DEEP 副本 - 通过在每个依赖项对象上调用 clone() 并将引用分配给包装器克隆中的实例变量来处理对依赖项的引用。
我知道这很长,但它非常清楚地说明了为什么 clone() 比“new”更快 - 只是将对象的状态作为二进制字符串抓取并复制它而无需任何“思考”/检查。
要了解有关字节码的更多信息,请查看this article in DZone。
请记住....计算机科学中的一切都是假的,包括类对象,因为它们只是将相关结构和函数组合在一起的另一种抽象,可能除了硬件:),大多数人实际上认为属于计算机工程,而不是 CS。