for、clone、System.arraycopy、Arrays.copyOf
public class Test {
public static final int size = 1000000;
/**
* SystemArrayCopy
*/
public static void copyBySystemArrayCopy(String[] strArray){
long startTime = System.nanoTime();
String[] destArray = new String[size];
System.arraycopy(strArray, 0, destArray, 0, strArray.length);
long endTime = System.nanoTime();
System.out.println("System.arraycopy: "+(endTime - startTime));
}
/**
* Clone
*/
public static void copyByClone(String[] strArray){
long startTime = System.nanoTime();
String[] destArray = strArray.clone();
long endTime = System.nanoTime();
System.out.println("Clone: "+(endTime - startTime));
}
/**
* ArraysCopyOf
*/
public static void copyByArraysCopyOf(String[] strArray){
long startTime = System.nanoTime();
String[] destArray = Arrays.copyOf(strArray, strArray.length);
long endTime = System.nanoTime();
System.out.println("Arrays.copyOf: "+(endTime - startTime));
}
/**
* For
* @param strArray
*/
public static void copyByFor(String[] strArray){
long startTime = System.nanoTime();
String[] destArray = new String[size];
for (int i = 0; i < strArray.length; i++){
destArray[i] = strArray[i];
}
long endTime = System.nanoTime();
System.out.println("For: "+(endTime - startTime));
}
public static void main(String[] args) {
String[] strArray = new String[size];
for (int i = 0; i < size; i++){
strArray[i] = "apple";
}
copyBySystemArrayCopy(strArray);
copyByClone(strArray);
copyByArraysCopyOf(strArray);
copyByFor(strArray);
}
}
输出:
System.arraycopy: 2083932
Clone: 2479159
Arrays.copyOf: 2573155
For: 7158382
结论:在数组的长度不是很大的时候,基本遵循的规律:System.arraycopy >Object.clone>Arrays.copyOf > for
原因总结:
1.for循环拷贝(速度相对比较慢)
for的速度之所以最慢是因为下标表示法每次都从起点开始寻位到指定下标处(现代编译器应该对其有进行优化,改为指针),另外就是它每一次循环都要判断一次是否达到数组最大长度和进行一次额外的记录下标值的加法运算。
2.Arrays.copyOf(浅拷贝)
查看Arrays.copyOf的源码可以发现,它其实本质上是调用了System.arraycopy。之所以时间差距比较大,是因为很大一部分开销全花在了Math.min函数上了。所以,相比之下,System.arraycopy效率要高一些。
JDK1.8的copyOf源码:
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
3.Object.clone
clone()比较特殊,对于对象而言,它是深拷贝,但是对于数组而言,它是浅拷贝。
数组拷贝
对于数组而言,它不是简单的将引用赋值为另外一个数组引用,而是创建一个新的数组。但是我们知道,对于数组本身而言,它的元素是对象的时候,本来数组每个元素中保存的就是对象的引用,所以,拷贝过来的数组自然而言也是对象的引用,所以对于数组对象元素而言,它又是浅拷贝。
4.System.arraycopy(浅拷贝)
这个是系统提供的拷贝方式,也是我们推荐使用的拷贝方式,它是浅拷贝,也就是说对于非基本类型而言,它拷贝的是对象的引用,而不是去新建一个新的对象。通过它的代码我们可以看到,这个方法不是用java语言写的,而是底层用c或者c++实现的,因而速度会比较快。
System.arraycopy()源码:
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
可以看到是native方法:native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中,C++编写的 底层函数,为JDK的底层函数。 可以将native方法比作Java程序同C程序的接口。