Arrays.copyOf()与System.arraycopy()的区别

简介: Arrays.copyOf()与System.arraycopy()的区别

利用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方法的源码实现:


2.png

Arrays的copyOf()方法传回的数组是新的数组对象,改变传回数组中的元素值,不会影响原来的数组。(在下面的图中将做具体解释)

copyOf()的第二个自变量指定要建立的新数组长度,如果新数组的长度超过原数组的长度,则保留数组默认值(默认值为0)

下面对此段代码在内存中的存储做一个图示:


2.png

首先我们在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方法的声明:

2.png将一个原始的数组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方法会速度更快些


相关文章
Arrays.asList、ArrayList.subList使用规范
Arrays.asList、ArrayList.subList使用规范
|
Java C++
List.of() Vs Arrays.asList()
在上面的示例中,List.of() 用于创建不可变的颜色列表。任何通过添加或删除元素来修改列表的尝试都将导致抛出异常。 Arrays.asList() 当我们想要由指定数组支持的固定大小(可序列化)集合时,请使用此方法。对返回集合的任何更改也将写入原始数组。 java
78 0
|
Java 编译器 索引
深入解析Java中的数组复制:System.arraycopy、Arrays.copyOf和Arrays.copyOfRange
当涉及到在Java中处理数组时,有许多方法可供选择,其中一些包括`System.arraycopy()`、`Arrays.copyOf()`和`Arrays.copyOfRange()`。这些方法允许您在不同的数组之间复制数据,但它们之间有一些细微的差异。在本篇博客文章中,我们将深入探讨这些方法,以便您了解何时使用它们以及如何正确使用它们。
564 1
|
Java
Arrays.asList()方法 讲解
Arrays.asList()方法 讲解
130 0
CTO:在项目中使用Arrays.asList、ArrayList.subList,就立马滚
1. 使用Arrays.asList的注意事项 1.1 可能会踩的坑 先来看下Arrays.asList的使用:
|
Java C++ 索引
Arrays.asList() vs Collections.singletonList()
看了 IDEA 的告警: 与 Collections.singletonList 比,使用 Arrays.asList 来生成一个list是否更有优势?后者还能使得返回的list不可变。
152 0
|
Java API
Arrays.asList注意事项
Arrays.asList注意事项
|
安全 Java API
Arrays.asList 解析
快速学习方法的定义 | 学习笔记
102 0
Arrays.asList() 和 new ArrayList() 的区别(详解)
Arrays.asList() 和 new ArrayList() 的区别(详解)
277 0
Arrays.asList() 和 new ArrayList() 的区别(详解)