测试说明:
数组复制其实是很简单的操作,先分配内存再挨个赋值即可。但是 Java 源码却提供了一个复制数组的 native(本地)方法。
函数原型如下,位于 java.lang.System
类当中:
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
那我就想了,这么简单的一个操作,究竟是自己去实现呢,还是调用 Java 自带的本地方法呢?
既然有了这样的选择,那当然是效率底下见真章了。
测试代码
基于 JDK1.8,分两次测试,第一次测试了数组长度为 100,1000 和 10000 三种情况,第二次测试了 50,100,1000,10000 四种情况,计时单位为纳秒(毫秒级上没差,所以有时也不用太过纠结)。
public class Test {
public static void main(String[] argus){
//JDK 1.8
int[] a50 = new int[50];
int[] a100 = new int[100];
int[] a1000 = new int[1000];
int[] a10000 = new int[10000];
long t1,t2,t3;
//长度为50时的效率对比
// int[] b50 = new int[50];
// t1 = System.nanoTime();
// for(int i = 0; i < b50.length; ++i){
// b50[i] = a50[i];
// }
// t2 = System.nanoTime();
// System.arraycopy(a50, 0, b50, 0, a50.length);
// t3 = System.nanoTime();
// System.out.println("数组长度为50时效率测试:");
// System.out.println("自己复制:"+(t2-t1));
// System.out.println("本地方法复制:"+(t3-t2));
//长度为100时的效率对比
int[] b100 = new int[100];
t1 = System.nanoTime();
for(int i = 0; i < b100.length; ++i){
b100[i] = a100[i];
}
t2 = System.nanoTime();
System.arraycopy(a100, 0, b100, 0, a100.length);
t3 = System.nanoTime();
System.out.println("数组长度为100时效率测试:");
System.out.println("自己复制:"+(t2-t1));
System.out.println("本地方法复制:"+(t3-t2));
//长度为1000时的效率对比
int[] b1000 = new int[1000];
t1 = System.nanoTime();
for(int i = 0; i < b1000.length; ++i){
b1000[i] = a1000[i];
}
t2 = System.nanoTime();
System.arraycopy(a1000, 0, b1000, 0, a1000.length);
t3 = System.nanoTime();
System.out.println("数组长度为1000时效率测试:");
System.out.println("自己复制:"+(t2-t1));
System.out.println("本地方法复制:"+(t3-t2));
//长度为10000时的效率对比
int[] b10000 = new int[10000];
t1 = System.nanoTime();
for(int i = 0; i < b10000.length; ++i){
b10000[i] = a10000[i];
}
t2 = System.nanoTime();
System.arraycopy(a10000, 0, b10000, 0, a10000.length);
t3 = System.nanoTime();
System.out.println("数组长度为10000时效率测试:");
System.out.println("自己复制:"+(t2-t1));
System.out.println("本地方法复制:"+(t3-t2));
}
}
代码运行结果
上面代码的运行结果如下:

如果将长度为 50 的情况解注释,运行情况如下:

结论
在我只测试 100,1000,10000 三种情况时,我以为 native 方法在数组长度较短时表现不好,而在数组长度较长时明显优于自己写代码复制。但当我加入 50 这种情况时,我发现我错了。我猜测是 native 方法仅在第一次复制时运行时间较长(可能初始时需要配置资源),之后再运行速度均明显快于自己写循环复制。
下面我将在做一组横向对比来验证猜想,运行四次 1000 的情况:
public class Test {
public static void main(String[] argus){
//JDK 1.8
int[] a1000 = new int[1000];
int[] b1000 = new int[1000];
int[] c1000 = new int[1000];
int[] d1000 = new int[1000];
int[] e1000 = new int[1000];//复制到此数组
long t1,t2,t3;
//长度为1000时的效率对比
t1 = System.nanoTime();
for(int i = 0; i < e1000.length; ++i){
e1000[i] = a1000[i];
}
t2 = System.nanoTime();
System.arraycopy(e1000, 0, a1000, 0, e1000.length);
t3 = System.nanoTime();
System.out.println("数组长度为1000时效率测试:");
System.out.println("自己复制:"+(t2-t1));
System.out.println("本地方法复制:"+(t3-t2));
//长度为1000时的效率对比
t1 = System.nanoTime();
for(int i = 0; i < e1000.length; ++i){
e1000[i] = b1000[i];
}
t2 = System.nanoTime();
System.arraycopy(e1000, 0, b1000, 0, e1000.length);
t3 = System.nanoTime();
System.out.println("数组长度为1000时效率测试:");
System.out.println("自己复制:"+(t2-t1));
System.out.println("本地方法复制:"+(t3-t2));
//长度为1000时的效率对比
t1 = System.nanoTime();
for(int i = 0; i < e1000.length; ++i){
e1000[i] = c1000[i];
}
t2 = System.nanoTime();
System.arraycopy(e1000, 0, c1000, 0, e1000.length);
t3 = System.nanoTime();
System.out.println("数组长度为1000时效率测试:");
System.out.println("自己复制:"+(t2-t1));
System.out.println("本地方法复制:"+(t3-t2));
//长度为1000时的效率对比
t1 = System.nanoTime();
for(int i = 0; i < e1000.length; ++i){
e1000[i] = d1000[i];
}
t2 = System.nanoTime();
System.arraycopy(e1000, 0, d1000, 0, e1000.length);
t3 = System.nanoTime();
System.out.println("数组长度为1000时效率测试:");
System.out.println("自己复制:"+(t2-t1));
System.out.println("本地方法复制:"+(t3-t2));
}
}
运行结果如下:

所以确实是 native 方法在第一次运行时可能需要进行资源配置,稍费一些时间,但在数组长度较长时,依然快于自己写代码复制。所以当我们的程序需要进行多次的大数组复制时,推荐调用 native(本地)方法去复制,效率较高。
网友评论