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方法会速度更快些


相关文章
|
8月前
|
存储 关系型数据库 MySQL
携程面试:100 亿分库分表 如何设计? 核弹级 16字真经, 让面试官彻底 “沦陷”,当场发offer!
携程面试:100 亿分库分表 如何设计? 核弹级 16字真经, 让面试官彻底 “沦陷”,当场发offer!
携程面试:100 亿分库分表 如何设计?  核弹级 16字真经, 让面试官彻底 “沦陷”,当场发offer!
|
Android开发
Android基于gradle task检查各个module之间资源文件冲突情况
Android基于gradle task检查各个module之间资源文件冲突情况
Android基于gradle task检查各个module之间资源文件冲突情况
|
11月前
|
SQL DataWorks 搜索推荐
DataWorks产品评测与最佳实践体验报告
DataWorks是阿里巴巴云推出的一款高效数据处理平台,通过内置的数据集成工具和ETL功能,实现了多源数据的自动化处理与分析。本文介绍了DataWorks在用户画像分析中的应用实践,展示了其如何帮助企业高效管理数据资源,支持决策制定及营销优化。同时,文章还评测了DataWorks的产品体验,包括开通流程、功能满足度等方面,并与其它数据开发平台进行了比较,突出了DataWorks在易用性、性能和生态完整性上的优势。最后,对Data Studio新版本中的Notebook环境进行了初步探索,强调了其在提升开发效率方面的价值。
387 16
|
资源调度 关系型数据库 MySQL
docker制作compose
本文介绍了Docker Compose的基本使用,包括安装、创建`docker-compose.yml`文件定义服务,以及如何使用环境变量和卷来配置多容器应用的步骤。
627 1
docker制作compose
|
IDE Java 开发工具
IntelliJ IDEA高效调试技巧:提升你的调试效率
在Java开发中,调试是开发过程中不可或缺的一部分。IntelliJ IDEA作为一款强大的IDE,提供了丰富的调试功能,帮助开发者更高效地定位和解决问题。本文将分享一些高手必会的IDEA调试技巧,让你的调试工作事半功倍。
259 0
|
资源调度 运维 前端开发
超强开源全能日程助手—揭秘FullCalendar
超强开源全能日程助手—揭秘FullCalendar
807 3
|
Java API 开发者
【面试题精讲】SPI 和 API 有什么区别?
【面试题精讲】SPI 和 API 有什么区别?
|
Java 文件存储
设计优雅的接口:实现最佳实践与方法论
设计优雅的接口:实现最佳实践与方法论
|
缓存 监控 安全
API网关的用途
【8月更文挑战第23天】
669 0
|
物联网 程序员 语音技术
STM32智能小车(循迹、跟随、避障、测速、蓝牙、wife、4g、语音识别)总结-3
STM32智能小车(循迹、跟随、避障、测速、蓝牙、wife、4g、语音识别)总结
STM32智能小车(循迹、跟随、避障、测速、蓝牙、wife、4g、语音识别)总结-3