Java中数组的拷贝方式

之前学习了List架构, 在List集合框架下大量使用了Arrays.copyOfSystem.arraycopy()来做数组拷贝. 今天就来学习下Java中数组拷贝的3中方式:循环拷贝,克隆方法拷贝,System.arraycopy拷贝. 文章主要分为下面几个部分:

  1. 3种拷贝方式的介绍
  2. 3种拷贝方式的效率比较
  3. System.arraycopy和Arrays.copyOf()的区别

3种拷贝方式的介绍

循环拷贝

循环拷贝的形式如下:创建一个新数组,用for循环把原来数组的元素set到新的数组当中.

1
2
3
4
5
6
7
/* 循环拷贝 */
private static void copyByLoop(String[] arr) {
String[] destArray = new String[SIZE];
for (int i = 0; i < arr.length; i++) {
destArray[i] = arr[i];
}
}

克隆方法拷贝

这个方式是利用数组的clone()方法来完成对数组的拷贝, 代码如下:

1
2
3
4
/* 克隆函数拷贝 */
private static void copyByClone(String[] arr) {
String[] destArray = arr.clone();
}

System.arraycopy拷贝

这个方式是创建一个新数组, 然后调用本地方法System.arraycopy来完成对新数组的拷贝. System.arraycopy的信息下面会讲到. 这种形式的代码如下:

1
2
3
4
5
/* System.arraycopy拷贝 */
private static void copyBySystemCopy(String[] arr) {
String[] destArray = new String[SIZE];
System.arraycopy(arr, 0, destArray, 0, arr.length);
}

3种拷贝方式的效率比较

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.archerda.ArrayCopy;
/**
* Java中数组拷贝的3种方式效率比较
* Created by luohd on 2016/9/7.
*/
public class Main {
private static final int SIZE = 1000000;
public static void main(String[] args) throws Exception{
String[] arr1 = new String[SIZE];
for (int i = 0; i < SIZE; ++i) {
arr1[i] = String.valueOf(i);
}
Thread.sleep(10);
copyByLoop(arr1);
String[] arr2 = new String[SIZE];
for (int i = 0; i < SIZE; ++i) {
arr2[i] = String.valueOf(i);
}
Thread.sleep(10);
copyByClone(arr2);
String[] arr3 = new String[SIZE];
for (int i = 0; i < SIZE; ++i) {
arr3[i] = String.valueOf(i);
}
Thread.sleep(10);
copyBySystemCopy(arr3);
}
/* 循环拷贝 */
private static void copyByLoop(String[] arr) {
Long startTime = System.currentTimeMillis();
String[] destArray = new String[SIZE];
for (int i = 0; i < arr.length; i++) {
destArray[i] = arr[i];
}
Long endTime = System.currentTimeMillis();
System.out.println("copyByLoop cost: " + (endTime - startTime));
}
/* 克隆函数拷贝 */
private static void copyByClone(String[] arr) {
Long startTime = System.currentTimeMillis();
String[] destArray = arr.clone();
Long endTime = System.currentTimeMillis();
System.out.println("copyByClone cost: " + (endTime - startTime));
}
/* System.arraycopy拷贝 */
private static void copyBySystemCopy(String[] arr) {
Long startTime = System.currentTimeMillis();
String[] destArray = new String[SIZE];
System.arraycopy(arr, 0, destArray, 0, arr.length);
Long endTime = System.currentTimeMillis();
System.out.println("copyBySystemCopy cost: " + (endTime - startTime));
}
}

输出结果, 单位ms:

SIZE copyByLoop copyByClone copyBySystemCopy
100000(10w) 3 0 0
1000000(100w) 7 1 1
5000000(500w) 14 6 5
10000000(1kw) 25 13 11

结论

  1. 使用for循环的方式, 将数组的每个元素进行复制或复制指定元素, 效率差;
  2. 使用clone方法, 效率高. 但是得到的是数组的值, 而不是引用, 又不能指定元素, 灵活性差;
  3. 使用System.arraycopy, 可以灵活复制, 由于是JNI方法, 效率高, 值得推荐;

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

System.arraycopy

System.arraycopy的方法声明如下:

1
2
3
4
5
public static native void arraycopy(Object src,
int srcPos,
Object dest,
int destPos,
int length);

其中,

  • src: 原数组
  • srcPos: 原数组开始拷贝位置
  • dest: 目标数组, 也就是要拷贝的新数组
  • destPos: 目标数组拷贝的开始位置
  • length: 拷贝的长度

Arrays.copyOf

Arrays.copyOf的方法如下:

1
2
3
4
5
6
7
8
9
10
11
public static <T,U> T[] copyOf(U[] original,
int newLength,
Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}

其中:

  • original: 原数组
  • newLength: 返回数组的长度, 也就是新数组长度
  • newType: 返回数组的类型

区别

  1. System.arraycopy需要传入一个新数组, Arrays.copyOf不用传入新数组, 它会在方法内部新建数组,;
  2. Arrays.copyOf也是调用System.arraycopy来完成数组拷贝;

参考文档