package InterviewDirectory.binaryTree_example.System.arraycopy_Arrays;
import java.util.Arrays;
/**
* Created by xxx on 2018/3/18.
*/
public class copyOf_clone_for {
/**
* System.arraycopy (浅拷贝)
* Arrays.copyOf(浅拷贝),
* Object.clone(对于对象而言,它是深拷贝,但是对于数组而言,它是浅拷贝)
* for
*/
private static final byte[] buffer = new byte[1024*10];
static {
for (int i = 0; i < buffer.length; i++) {
buffer[i] = (byte) (i & 0xFF);
}
}
private static long startTime;
public static void main(String[] args) {
startTime = System.nanoTime();
methodFor();
calcTime("methodFor");
startTime = System.nanoTime();
methodClone();
calcTime("methodClone");
startTime = System.nanoTime();
methodArraysCopyOf();
calcTime("methodArraysCopyOf");
startTime = System.nanoTime();
methodSystemArraycopy();
calcTime("methodSystemArraycopy");
}
private static void methodFor() {
byte[] newBuffer = new byte[buffer.length];
for(int i=0;iprivate static void methodClone() {
byte[] newBuffer = buffer.clone();
}
private static void methodArraysCopyOf() {
byte[] newBuffer = Arrays.copyOf(buffer, buffer.length);
}
private static void methodSystemArraycopy() {
byte[] newBuffer = new byte[buffer.length];
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
}
private static void calcTime(String method) {
long endTime = System.nanoTime();
System.out.println(method + " cost " +(endTime-startTime)+ " nanosecond");
}
}
(1)for循环拷贝(速度相对比较慢)
for的速度之所以最慢是因为下标表示法每次都从起点开始寻位到指定下标处(现代编译器应该对其有进行优化,改为指针),另外就是它每一次循环都要判断一次是否达到数组最大长度和进行一次额外的记录下标值的加法运算。
(2)Arrays.copyOf(浅拷贝)
查看Arrays.copyOf的源码可以发现,它其实本质上是调用了System.arraycopy。之所以时间差距比较大,是因为很大一部分开销全花在了Math.min函数上了。所以,相比之下,System.arraycopy效率要高一些。
public static byte[] copyOf(byte[] original, int newLength) {
byte[] copy = new byte[newLength];
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
return copy;
}
(3)Object.clone
clone()比较特殊,对于对象而言,它是深拷贝,但是对于数组而言,它是浅拷贝。
protected native Object clone() throws CloneNotSupportedException;
这里也有native关键字,所以也是底层的c语言实现的。
还要注意的是,这里修饰符是protected,也就是说,我们创建了一个Object类以后,是不能直接调用这个clone()方法的,因为protected关键字只允许同一个包内的类和它的子类调用,所以我们声明一个object类时,肯定不是同一个包内,所以就不能去调用它。
要调用这个方法,就需要我们写一个类,然后声明实现cloneable接口就好了,不需要去显示地声明继承于object,因为java中的类如果不显示说明父类的话,默认父类就是object。然后我们继承这个方法:
@Override
public Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
这里需要是,为了能够在不同包内去调用这个方法,我们需要把这个权限升级为public。现在我们就可以调用这个类的clone()方法去拷贝我们的类了。
class Aby implements Cloneable{
public int i;
public Aby(int i) {
this.i = i;
}
@Override
public Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
public class Solution {
public static void main(String[] args) throws CloneNotSupportedException {
Aby aby1 = new Aby(1);
Aby aby2 = (Aby) aby1.clone();
aby1.i = 2;
System.out.println(aby1.i); //2
System.out.println(aby2.i); //1
Aby[] arr = {aby1,aby2};
Aby[] arr2 = arr.clone();
arr2[0].i = 3;
System.out.println(arr[0].i); //3
System.out.println(arr2[0].i); //3
}
}
(4)System.arraycopy(浅拷贝)
这个是系统提供的拷贝方式,也是我们推荐使用的拷贝方式,它是浅拷贝,也就是说对于非基本类型而言,它拷贝的是对象的引用,而不是去新建一个新的对象。通过它的代码我们可以看到,这个方法不是用java语言写的,而是底层用c或者c++实现的,因而速度会比较快。
System.arraycopy()源码。可以看到是native方法:native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中,C++编写的 底层函数,为JDK的底层函数。 可以将native方法比作Java程序同C程序的接口,。
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);