您的位置:首页 > 编程语言 > Java开发

java 复制数组的方法总结

2017-04-27 19:34 453 查看
在看ArrayList源码的时候出现了好多关于数组扩容(也就是复制数组的操作),如么如果换作我们,如何进行数组的复制操作呢

for循环复制

我们首先想到的是for循环,来上代码

int[] arr = {4, 1, 2, 9, 10, 12, 15};
int len = arr.length;

int[] copyArr = new int[len];
for(int i = 0; i < len; i++){
copyArr[i] = arr[i];
}

System.out.println(Arrays.toString(copyArr));


打印[4, 1, 2, 9, 10, 12, 15]复制成功

for循环数组扩容

int[] arr = {4, 1, 2, 9, 10, 12, 15};
int len = arr.length;

int newLen = 20;
int[] copyArr = new int[newLen];
for(int i = 0; i < len; i++){
copyArr[i] = arr[i];
}
System.out.println(Arrays.toString(copyArr));


打印[4, 1, 2, 9, 10, 12, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],扩容成功

要是工作中老是遇到复制数组该怎么办呢?很简单,封装个静态方法不就可以了。等等,既然智商如我这么低的人都知道封装方法,那前辈们肯定封装好了,那就找一找呗

Arrays.copyf方法

千辛万苦在Arrays类里找到了此方法,因为Java基本类型不支持泛型,所以此方法对8种基本类型重载,下面列举出int类型和泛型的两个重载方法的代码

基本类型

public static int[] copyOf(int[] orginal, int newLength){
int [] copy = new int[newLength];
System.arraycopy(original, 0, copy
4000
, 0, Math.min(original.length, newLength);
return copy;
}


有意思的是Math.min(original.length, newLength);,会取原始数组长度和newLength的最小值

所以当newLength < original.length时,相当于对原始数组的截取

int[] arr = {4, 1, 2, 9, 10, 12, 15};
int[] copyArr = Arrays.copyOf(arr, 3);
System.out.println(Arrays.toString(copyArr));
//[4, 1, 2]


当newLength > original.length时,相当于对原始数组的扩容

int[] arr = {4, 1, 2, 9, 10, 12, 15};
int[] copyArr = Arrays.copyOf(arr, 13);
System.out.println(Arrays.toString(copyArr));
//[4, 1, 2, 9, 10, 12, 15, 0, 0, 0, 0, 0, 0]


当newLength == original.length时呢。别问我了,我不知道

泛型

public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
//判断如果新类型如果是Object[].class则直接构造一个Object[],如果不是,通常反射创建一个数组
//这么做是为了提升效率,也可能是因ArrayList底层是用Object[]做为容器,提高ArrayList内部扩容的效率
@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;
}


原理介绍完了,使用方式和上面那个基本一样。

Arrays.copyOfRange

Arrays.copyOfRange方法跟Arrays.copyOf方法一样,也有对八种基本类型的重载操作

基本类型

以int类型代码作分析

public static int[] copyOfRange(int[] original, int from, int to){
int newLength = to - from;
if(newLength < 0){
throw new IllegalArugmentException(from + " > " + to);
}
int[] copy = new int[newLength];
System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength));
return copy;
}


最不好理解的地方应该在
System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength));
这里吧

我发现在Java所有的截取操作中都是截头不截尾(包含from,不包含to),那么上述代码的意思就是从原数组的from处复制到copy数组,以0开始,复制Math.min(original.length - from, newLength)个

System.arraycopy

最低层的数组复制就是

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


这个方法了,一个native方法

具体的用法是从src的srcPos处把length个长度的元素从dest的destPos处复制进dest数组里

我们可以用这个方法来复制数组

int[] arr = {1, 2 ,3 ,4};
int[] copy = new int[arr.length];
System.arraycopy(arr, 0, copy, 0, arr.length);
System.out.println(Arrays.toString(copy)); //[1, 2, 3, 4]


模拟ArrayList的add(int index, E e)操作

//模拟ArrayList的内置数组
int[] arr = {1, 2 ,3 ,4};
//模拟ArrayList的内置数组扩容
int[] copy = Arrays.copyOf(arr, arr.length + arr.length >> 1);
//模拟ArrayList的size
int size = 4;
//模拟要插入的索引
int index = 3;
//将数组index处整体向后移动一位
System.arraycopy(copy,  index, copy, index + 1, size-index);

System.out.println(Arrays.toString(copy)); //[1, 2, 3, 4, 4, 0, 0, 0, 0, 0]
//设置index处的值
copy[index] = 100;
System.out.println(Arrays.toString(copy)); //[1, 2, 3, 100, 4, 0, 0, 0, 0, 0]


其实ArrayList的底层实现大体就像上面那样
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: