利用copyof方法进行拷贝
代码示例:
//定义一个数组array3 int[] array = {1, 2, 3, 4, 5, 6}; //copyOf方法是用来拷贝数组的一种方法,括号中放入的分别为引用和想要拷贝多长的数组的长度值 int[] array2 = Arrays.copyOf(array, 10); //输出结果为[1, 2, 3, 4, 5, 6] System.out.println(Arrays.toString(array)); //输出结果为[1, 2, 3, 4, 5, 6, 0, 0, 0, 0] System.out.println(Arrays.toString(array2));
此处我们利用copyof方法来进行数组的拷贝,此处我们可以看下copyof方法的源码实现:
Arrays的copyOf()方法传回的数组是新的数组对象,改变传回数组中的元素值,不会影响原来的数组。(在下面的图中将做具体解释)
copyOf()的第二个自变量指定要建立的新数组长度,如果新数组的长度超过原数组的长度,则保留数组默认值(默认值为0)
下面对此段代码在内存中的存储做一个图示:
首先我们在main方法中定义了一个数组array并进行了初始化,那么首先在栈上开辟main方法的栈帧,并为引用array开辟内存,此时引用array的数组对象的地址存储在其内存中,逻辑上引用array指向了其数组对象,此时我们定义了一个新的数组array2,并且调用了copyof方法,那么在栈上为copyof开辟一个新的栈帧并在main方法的栈帧中再为array2开辟一个新的内存,然后再为copyof方法内部的局部变量copy在copyof方法的栈帧上分配内存,此时通过copeof方法的调用后我们的引用copy有了一个新的数组对象,此时同样copy引用指向了这个新的数组对象,并且当我们将copyof方法的返回值(即copy数组)赋给我们所定义的新的数组array2后,同样array2这个引用此时也指向了这个新的数组对象(原因是地址传递).
同时在这里介绍下copefOf方法的变形也就是copeOfRange方法,首先我们来看下代码示例:
int[] array= {1, 2, 3, 4, 5, 6}; int[] ret=Arrays.copyOfRange(array,1,5); int[] ret1=Arrays.copyOfRange(array,1,7); //输出结果为[2, 3, 4, 5] System.out.println(Arrays.toString(ret)); //输出结果为[2, 3, 4, 5, 6, 0] System.out.println(Arrays.toString(ret1));
首先我们来看下copyOfRange方法的声明:
将一个原始的数组original,从下标from开始复制,复制到下标to,生成一个新的数组。
注意这里包括下标from,但不包括上标to。
例如在上面的代码中,我们从array数组中下标为1的地方开始复制,复制到下标为5的地方,但并不复制下标为5处的本身的数字,那么此时复制的数字有2,3,4,5
而当to处的的下标值超过了被复制数组array下标的最大值时,例如上面的代码中,array的下标值最大到5,而此时from下标值为1,to的下标值为7,7>5,相当于当我们复制完array[5]处的数字后,此时array不能再提供数字让我们复制了,则此时ret1[6]的值为0,即为默认值,所以总结结论得当to处的的下标值超过了被复制数组array下标的最大值时,其后面所放的数字统一为0.
利用arraycopy方法进行拷贝
代码示例:
int[] array5 = {1, 2, 3, 4, 5, 6}; int[] array6 = new int[array5.length]; /*表示从array5数组的0下标开始复制6个数字到array6数组当中,并且在放入arrray6数组当中时 也是从0下标开始放入*/ System.arraycopy(array5, 0, array6, 0, 6); //输出结果为[1, 2, 3, 4, 5, 6] System.out.println(Arrays.toString(array5)); //输出结果为[1, 2, 3, 4, 5, 6] System.out.println(Arrays.toString(array6));
首先观察先System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)的声明:
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
src - 源数组(即被复制的数组)。
srcPos - 源数组中的起始位置(表示可以从源数组的任意一个下标处开始复制)。
dest - 目标数组(即复制后的数组)。
destPos - 目标数组中的起始位置(表示可以让复制过来的数字按照下标顺序从其要在新的目标数组中所放入的位置开始有序插入)。
此处有两种情况需要注意:
情况一:此时我们修改下代码:当我们要复制的数组长度大于原数组长度时,例如我们设为10
int[] array5 = {1, 2, 3, 4, 5, 6}; int[] array6 = new int[10]; /*表示从array5数组的1下标开始复制5个数字到array6数组当中,并且在放入arrray6数组当中时,是从2下标开始放入的,那么此时array6[0],array6[1]的默认值变为0,并且此时已经占用两个位置后,array6中能放入的数字变为了8个,所以 此时我们复制过来的数字能放入array6这个数组当中的有2,3,4,5,6.接着array6[6]=array6[7]=array6[8]=array6[9]=0.
此处一定要注意如果srcPos+length>src.length,那么此时便会发生数组下标越界异常,例如此时length值若变为6,1+6>6,那么运行代码时便会出现数组下标越界异常,原因是从原数组下标为1处开始往后复制6个时,当我们复制到下标为5处的地方,此时已经没有数组再让我们复制了。
System.arraycopy(array5, 1, array6, 2, 5); //输出结果为[1, 2, 3, 4, 5, 6] System.out.println(Arrays.toString(array5)); //输出结果为[0, 0, 2, 3, 4, 5,0,0,0,0] System.out.println(Arrays.toString(array6));
情况二:此时我们修改下代码:当我们要复制的数组长度等于原数组长度时
int[] array5 = {1, 2, 3, 4, 5, 6}; int[] array6 = new int[array5.length]; /*表示从array5数组的1下标开始复制4个数字到array6数组当中,并且在放入arrray6数组当中时,是从2下标开始放入的,那么此时array6[0],array6[1]的默认值变为0,并且此时已经占用两个位置后,array6中能放入的数字变为了4个,所以 此时我们复制过来的数字能放入array6这个数组当中的只有2,3,4,5.
此处一定要注意length的取值最多(<=)为array5.length-destPos,如果超过此时便会发生数组下标越界异常,例如此时length值若变为5,那么运行代码时便会出现数组下标越界异常,原因是array[6]数组中只能再放入4个了,而length的值是小于等于能插入的个数的.
System.arraycopy(array5, 1, array6, 2, 4); //输出结果为[1, 2, 3, 4, 5, 6] System.out.println(Arrays.toString(array5)); //输出结果为[0, 0, 2, 3, 4, 5] System.out.println(Arrays.toString(array6));
length - 要复制的数组元素的数量。(容易出错,需要注意)
该方法是用了native关键字,调用的为C++编写的底层函数,可见其为JDK中的底层函数。
面试题目:arraycopy方法和copyOf方法哪个拷贝速度更快呢?
答:arraycopy方法会比较快,原因是当我们浏览arraycopy方法源码时会发现其被native所修饰,我们都知道native方法是由C/C++代码来实现的,我们是看不到具体实现的,而且被native所修饰的方法一般有个特点就是速度块
所以arraycopy方法会速度更快些