System.arraycopy()方法使用

定义

public static native void arraycopy(Object src,  int srcPos, Object dest, int destPos, int length);

可以看到,它是一个静态本地方法,由虚拟机实现,效率自然比用java一个个复制高。

方法含义

从源数组src取元素,范围为下标srcPos到srcPos+length-1,取出共length个元素,存放到目标数组中,存放位置为下标destPos到destPos+length-1。

简单说,就是数组间的复制

应用

常用作数组的扩容,如ArrayList底层数组的扩容

参数

  • Object src:the source array. 源数组
  • int srcPos:starting position in the source array. 在源数组中,开始复制的位置
  • Object dest:the destination array. 目标数组
  • int destPos:starting position in the destination data. 在目标数组中,开始赋值的位置
  • int length:the number of array elements to be copied. 被复制的数组元素的数量

过程详解

以下面这个例子进行分析

public class SystemArrayCopy {public static void main(String[] args) {int[] src = {1, 2, 3, 4};int[] dest = new int[5];System.arraycopy(src, 0, dest, 1, 4);for (Object o : dest) {System.out.println(o);}}
}
/*
0 1 2 3 4
*/
src = |1|2|3|4|
dest = |0|0|0|0|0|
执行System.arraycopy(src, 0, dest, 1, 4);时
第一步:从源数组(src)中,从下标0开始取,取4个,也就是src[0]-src[3],即1 2 3 4四个数
第二步:把取出的数,按顺序,存放到目标数组(dest)中,从下标1开始存,存4个,也就是dest[1]-dest[4]
所以数组dest为:|0|1|2|3|4|

再来一个例子

public class SystemArrayCopy {public static void main(String[] args) {String[] src = {"aa", "bb", "cc", "cc"};String[] dest = new String[]{"a", "b", "c", "d", "e"};System.arraycopy(src, 1, dest, 2, 2);for (Object o : dest) {System.out.println(o);}}
}
/*
a b bb cc e
*/
String[] src = |"aa"|"bb"|"cc"|"cc"|
String[] dest = |"a"|"b"|"c"|"d"|"e"|
执行 System.arraycopy(src, 1, dest, 2, 2);时
第一步:从源数组(src)中,从下标1开始取,取2个,也就是src[1]-src[2],即"bb" "cc"两个字符串
第二步:把取出的数,按顺序,存放到目标数组(dest)中,从下标2开始存,存2个,也就是dest[2]-dest[3]
所以数组dest为:|"a"|"b"|"bb"|"cc"|"e"|

注意,目标数组下标范围外的元素不会改变!

深复制与浅复制

  1. 当数组为一维数组,且元素为基本类型或String类型时,属于深复制,即原数组与新数组的元素不会相互影响
  2. 当数组为多维数组,或一维数组中的元素为引用类型时,属于浅复制,原数组与新数组的元素引用指向同一个对象
  1. 这里说的影响,是两个数组复制后对应的元素,并不一定是下标对应
  2. String的特殊是因为它的不可变性

1. 一维数组,元素为基本类型

public class SystemArrayCopy {public static void main(String[] args) {String str1 = "aa";String str2 = "bb";String str3 = "cc";String str4 = "dd";String[] src = {str1, str2, str3, str4};String[] dest = new String[4];System.arraycopy(src, 0, dest, 0, 4);System.out.println("改变前");print("src = ", src);print("dest = ", dest);src[0] = "abcd";System.out.println("改变后");print("src = ", src);print("dest = ", dest);}private static void print(String string, String[] arr) {System.out.print(string);for (String str : arr) {System.out.print(str + " ");}System.out.println();}}
/*
改变前
src = aa bb cc dd
dest = aa bb cc dd
改变后
src = abcd bb cc dd
dest = aa bb cc dd
*/

可以看到,源数组第0个元素改变,并不会影响到目标数组

2. 多维数组

public class SystemArrayCopy {public static void main(String[] args) {int[] arr1 = {1, 2};int[] arr2 = {3, 4};int[] arr3 = {5, 6};int[] arr4 = {7, 8};int[][] src = new int[][]{arr1, arr2, arr3, arr4};int[][] dest = new int[4][];System.arraycopy(src, 0, dest, 0, 4);System.out.println("改变前");print("src = ", src);print("dest = ", dest);src[0][0] = 11111;System.out.println("改变后");print("src = ", src);print("dest = ", dest);}// 简单输出二维int数组的方法private static void print(String string, int[][] arr) {System.out.print(string);for (int[] a : arr) {for (int i : a) {System.out.print(i + " ");}System.out.print(",");}System.out.println();}
}
/*
改变前
src = 1 2 ,3 4 ,5 6 ,7 8 ,
dest = 1 2 ,3 4 ,5 6 ,7 8 ,
改变后
src = 11111 2 ,3 4 ,5 6 ,7 8 ,
dest = 11111 2 ,3 4 ,5 6 ,7 8 ,
*/

源数组改变后,目标数组也跟改变了,这就是浅复制

3. 一维数组,元素为引用类型

public class SystemArrayCopy {public static void main(String[] args) {People p1 = new People(11, "A");People p2 = new People(12, "B");People p3 = new People(13, "C");People p4 = new People(14, "D");People[] src = new People[]{p1, p2, p3, p4};People[] dest = new People[4];System.arraycopy(src, 0, dest, 0, 4);System.out.println("改变前");print("src = ", src);print("dest = ", dest);src[0].setAge(111);src[0].setName("AAA");System.out.println("改变后");print("src = ", src);print("dest = ", dest);}private static void print(String string, People[] arr) {System.out.print(string);for (People p : arr) {System.out.print(p + ", ");}System.out.println();}
}
public class People {private int age;private String name;// get set constructor toString
}
/*
改变前
src = People{age=11, name='A'}, People{age=12, name='B'}, People{age=13, name='C'}, People{age=14, name='D'},
dest = People{age=11, name='A'}, People{age=12, name='B'}, People{age=13, name='C'}, People{age=14, name='D'},
改变后
src = People{age=111, name='AAA'}, People{age=12, name='B'}, People{age=13, name='C'}, People{age=14, name='D'},
dest = People{age=111, name='AAA'}, People{age=12, name='B'}, People{age=13, name='C'}, People{age=14, name='D'},
*/

源数组改变后,目标数组也跟改变了,这就是浅复制

总结:只有数组为一维数组,并且元素为基本类型或String类型时,才是深复制,其它都属于浅复制

下图是System.arraycopy()复制的过程

异常

ArrayIndexOutOfBoundsException ArrayStoreException NullPointerException

1. ArrayIndexOutOfBoundsException

当数组越界时,抛出异常:ArrayIndexOutOfBoundsException

srcPos < 0 || destPos < 0 || length < 0
src.length < length + srcPos
dest.length < length + destPos
代码演示

// 1. srcPos < 0 || destPos < 0 || length < 0
public class SystemArrayCopy {public static void main(String[] args) {int[] src = {1, 2, 3, 4};int[] dest = new int[5];System.arraycopy(src, -1, dest, 0, 0);for (Object o : dest) {System.out.println(o);}}
}
/*
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsExceptionat java.lang.System.arraycopy(Native Method)at com.balsam.sources.SystemArrayCopy.main(SystemArrayCopy.java:13)
*/// 2. src.length < length + srcPos
public class SystemArrayCopy {public static void main(String[] args) {int[] src = {1, 2, 3, 4};int[] dest = new int[5];System.arraycopy(arr, 1, dest, 0, 4);for (Object o : dest) {System.out.println(o);}}
}
/*
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsExceptionat java.lang.System.arraycopy(Native Method)at com.balsam.sources.SystemArrayCopy.main(SystemArrayCopy.java:13)
*/// 3. dest.length < length + destPos
public class SystemArrayCopy {public static void main(String[] args) {int[] src = {1, 2, 3, 4};int[] dest = new int[3];System.arraycopy(src, 0, dest, 0, 4);for (Object o : dest) {System.out.println(o);}}
}
/*
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsExceptionat java.lang.System.arraycopy(Native Method)at com.balsam.sources.SystemArrayCopy.main(SystemArrayCopy.java:13)
*/

2. ArrayStoreException

当两数据的元素类型不匹配时,抛出异常:ArrayStoreException

src元素为dest元素的子类时,是可以复制的,特殊地,int不是Object的子类(或者说,不存在继承的概念),所以,下例中,把int[] src = {1, 2, 3, 4};改为Integer[] src = {1, 2, 3, 4};,是不会报错的

public class SystemArrayCopy {public static void main(String[] args) {int[] src = {1, 2, 3, 4};Object[] dest = new Object[3];System.arraycopy(src, 0, dest, 0, 4);for (Object o : dest) {System.out.println(o);}}
}
/*
Exception in thread "main" java.lang.ArrayStoreExceptionat java.lang.System.arraycopy(Native Method)at com.balsam.sources.SystemArrayCopy.main(SystemArrayCopy.java:13)
*/public class SystemArrayCopy {public static void main(String[] args) {Object[] src = {1, 2, 3, 4};int[] dest = new int[3];System.arraycopy(src, 0, dest, 0, 4);for (Object o : dest) {System.out.println(o);}}
}
/*
Exception in thread "main" java.lang.ArrayStoreExceptionat java.lang.System.arraycopy(Native Method)at com.balsam.sources.SystemArrayCopy.main(SystemArrayCopy.java:13)
*/

3. NullPointerException

当两个数组,有一个为null时,抛出异常:NullPointerException

public class SystemArrayCopy {public static void main(String[] args) {int[] src = {1, 2, 3, 4};int[] dest = null;System.arraycopy(src, 0, dest, 0, 4);for (Object o : dest) {System.out.println(o);}}
}
/*
Exception in thread "main" java.lang.NullPointerExceptionat java.lang.System.arraycopy(Native Method)at com.balsam.sources.SystemArrayCopy.main(SystemArrayCopy.java:13)
*/

最后关于几种数组复制的效率问题

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()。
  对于数组空间小的情况下,前三种差别不大,对于比较大的数组,便可以明显看出差别。

参考文章:

System.arraycopy()方法详解_qq_32440951的博客-CSDN博客_system.arraycopy

System.arraycopy()方法详解-jdk1.8_balsamspear的博客-CSDN博客_system.arraycopy

关于System.arrayCopy()方法 - YesterdayAndTomorrow - 博客园

System.arraycopy()方法使用相关推荐

  1. arraycopy java_Java System arraycopy()方法

    Java System arraycopy()方法 java.lang.System.arraycopy() 方法复制从指定源数组的数组,开始在指定的位置,到目标数组的指定位置. 阵列组件的子序列是从 ...

  2. 【集合类】 4 System:System.arraycopy方法解析

    文章目录 引言 1.System.arraycopy 1.1 深复制还是浅复制 1.2 一维数组和多维数组的复制的区别 1.2.1 一维数组 1.2.2 多维数组 1.3 线程安全,还是不安全 1.4 ...

  3. System.arraycopy方法的使用

    System.arraycopy: 一般用于数组的复制和数据替换,是System类中一个被关键词native修饰的方法. 源码: public static native void arraycopy ...

  4. java arraycopy()方法_Java学习之System.arraycopy()方法

    java.lang.System的静态方法arraycopy()可以实现数组的复制,讲课的老师说这个方法效率比较高,如果数组有成千上万个元素,那么用这个方法,比用for语句循环快不少.System提供 ...

  5. php arraycopy,System.arraycopy方法解释

    **/* * @param src the source array.源数组 * @param srcPos starting position in the source array.源数组要复制的 ...

  6. java arraycopy方法_Java System.arrayCopy()方法

    System提供了一个静态方法arraycopy(),我们可以使用它来实现数组之间的复制. 其函数原型是: /** * Copies an array from the specified sourc ...

  7. arraycopy用法_Java复制(拷贝)数组的4种方法:arraycopy()方法、clone() 方法、copyOf()和copyOfRan...

    所谓复制数组,是指将一个数组中的元素在另一个数组中进行复制.本文主要介绍关于 Java 里面的数组复制(拷贝)的几种方式和用法.在 Java 中实现数组复制分别有以下 4 种方法: Arrays 类的 ...

  8. System.arraycopy(src, srcPos, dest, destPos, length) 与 Arrays.copyOf(original, newLength)区别

    //System.arraycopy,只拷贝已存在的数组元素 int[] src = {0, 1, 2}; int[] dest = new int[3]; System.arraycopy(src, ...

  9. 1.13 复制(拷贝)数组的4种方法:arraycopy()方法、clone() 方法、copyOf()和copyOfRan

    所谓复制数组,是指将一个数组中的元素在另一个数组中进行复制.本文主要介绍关于 Java 里面的数组复制(拷贝)的几种方式和用法. 在 Java 中实现数组复制分别有以下 4 种方法: Arrays 类 ...

最新文章

  1. 参加第十一届开源黑客松大会有感:
  2. 邬贺铨院士:十问边缘计算!
  3. 算法-------无重复字符的最长子串(Java版)
  4. *【CodeForces - 122C 】Lucky Sum (bfs记录状态,二分查找,有坑)(或分块)
  5. linux 安装mysql 云盘_linux下 安装mysql教程
  6. 使用Python写的第一个网络爬虫程序
  7. [转]余弦cos计算相似度
  8. NumPy库---Axis理解
  9. 《SAP后勤模块实施攻略—SAP在生产、采购、销售、物流中的应用》——3.3 MRP结果评估概览...
  10. vm虚拟机win7安装镜像方法
  11. 电气工程及其自动化用matlab,计算机仿真技术与CAD--基于MATLAB的电气工程(电气工程及其自动化专业精品教材普通高等教育十三...
  12. 【高等数学笔记】闭包、孤立点、导集、内点、边界的关系
  13. Shell 进阶指南
  14. 中国电信php,一个基于中国电信开放应用平台的短信发送函数(PHP版)
  15. mysql slave 1062_mysql主从同步slave错误1062
  16. php文件断点上传文件,php大文件上传支持断点上传
  17. java手机号正则验证(中国手机号)
  18. 最简单的ESP8266的Wifi智能小车车教程
  19. 平安科技美国研究院院长韩玫:AI赋能传统行业,要知其然也知其所以然
  20. 抖音短视频数据抓取实战系列(三)——Fiddler抓取抖音用户详细信息数据

热门文章

  1. 机器学习的评价方法PRF
  2. Git:移除文件----git rm命令的使用
  3. Mucosal Immunology | 胃肠道内的NADPH氧化酶类和活性氧信号通路
  4. python opencv轻松去图片水印
  5. openstack Cinder 架构分析、高可用部署与核心功能解析
  6. java g1的并行,Java 11究竟比8快了多少?看看这个基准测试
  7. java启动依赖包问题_spring boot创建项目包依赖问题的解决
  8. 数据结构(一)-------- 树的图示
  9. 下属培养不起来?Leader只知道996,不懂教练技术!总监让他学习“GROW模型”
  10. 弹性盒模型中flex-grow 和flex的区别