关于System.arrayCopy()方法

java其实没有二维数组的概念,平常实现的二维数组只是元素是一维数组的一维数组,而数组也是引用类型,继承自Object类。数组是new出来的。这些性质也就导致arraycopy()二维数组时出现的问题。

1、首先对于一维数组,如果元素都是基础类型(如int,double等),使用arraycopy()方法后,是把原数组的值传给了新数组,属于值传递,故修改复制后的数组,原数组不受到影响。如果是不可变类如String,虽然属于引用传递,但是具有不可变的特征,故修改复制后的数组,原数组不受到影响。
2、对于二维数组,数组的第一维装的是一个一维数组的引用,第二维里是元素数值。对二维数组应用arraycopy()方法后,第一维的引用被复制给新数组的第一维,也就是两个数组的第一维都指向相同的“那些数组”。而这时改变其中任何一个数组的元素的值,其实都修改了“那些数组”的元素的值,所以原数组和新数组的元素值都一样了。

System.arraycopy()的实现方法:
首先查看System.arraycopy()的API
public static void arraycopy(Object src,
int srcPos,
Object dest,
int destPos,
int length)将指定源数组中的数组从指定位置复制到目标数组的指定位置。 阵列组件的一个子序列被从通过引用的源阵列复制src被引用的目标阵列dest 。 复制的组件数量等于length参数。 源阵列中位置srcPos至srcPos+length-1的组件分别复制到目标阵列的位置destPos至destPos+length-1 。
如果src个dest参数指代相同的数组对象,则被处理是否在位置上的部件进行复印srcPos通过srcPos+length-1首先被复制到一个临时的阵列length组分,然后将临时数组的内容被复制到的位置destPos通过destPos+length-1目标数组的。

其中 Arrays.copy是JDK1.6中引用的新方法。它调用了System.arraycopy完成相关数组的复制。
在JDK1.6中ArrayList的相关add remove等操作都是调用System.arraycopy来对其底层的Object[]elementData数组进行操作的。
LinkedList则使用一个Entry的内部类,其有指向next和previous的引用保存元素,它的遍历则先计算出所需index和size>>1(以为后的大小),确定是通过previous还是next遍历。
查看System.arraycopy() 的源码:
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
可以看到它是native方法,一般是借助C/C++实现的,Java无法直接访问到操作系统底层(如系统硬件等),为此Java使用native方法来扩展Java程序的功能。

  可以将native方法比作Java程序同C程序的接口,其实现步骤:

  1、在Java中声明native()方法,然后编译;

  2、用javah产生一个.h文件;

  3、写一个.cpp文件实现native导出方法,其中需要包含第二步产生的.h文件(注意其中又包含了JDK带的jni.h文件);

  4、将第三步的.cpp文件编译成动态链接库文件;

  5、在Java中用System.loadLibrary()方法加载第四步产生的动态链接库文件,这个native()方法就可以在Java中被访问了。

最后关于几种数组复制的效率问题:
1、for循环,手动复制
2、System.arraycopy()方法
3、Arrays.copyOf()方法
4、clone()方法
结论:
由于System.arraycopy()是最贴近底层的,其使用的是内存复制,省去了大量的数组寻址访问等时间,故效率最高。
对于Arrays.copyOf()方法查看源码可以看到:
public static int[] copyOf(int[] original, int newLength) {
int[] copy = new int[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
它是借助System.arraycopy()方法实现的,故效率次于System.arraycopy()
clone()方法效率是最低的,一般需要重写,clone的方法Object执行特定的克隆操作。 首先,如果此对象的类不实现接口Cloneable ,则抛出CloneNotSupportedException 。 请注意,所有数组都被认为是实现接口Cloneable ,并且数组类型T[]的clone方法的返回类型是T[] ,其中T是任何引用或原始类型。 否则,该方法将创建该对象的类的新实例,并将其所有字段初始化为完全符合该对象的相应字段的内容,就像通过赋值一样。 这些字段的内容本身不被克隆。 因此,该方法执行该对象的“浅拷贝”,而不是“深度拷贝”操作。如果需要“深度拷贝”操作,则需要递归clone()
对于数组空间小的情况下,前三种差别不大,对于比较大的数组,便可以明显看出差别。