浅拷贝与深拷贝的区别
浅拷贝:
只是增加了一个指针指向已存在的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。
深拷贝:
是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,不会受到原数组的影响
浅拷贝例子
-
直接复制
public static void main(String[] args) { int[] arrayA = {1, 2}; print(arrayA); int[] arrayB = arrayA; print(arrayB); arrayA[0] = 5; print(arrayA); print(arrayB); } private static void print(int[] array) { for (int i = 0; i < array.length; i++) { System.out.print(array[i]+" "); } System.out.println(); } //1 2 //1 2 //5 2 //1 2
-
如果数组类对象为引用对象,那所有深拷贝都是浅拷贝
深拷贝例子
-
for循环赋值
-
System.arraycopy方法实现数组的复制(需要准备好目标数组,并分配长度)
-
当数组为一维数组,且元素为基本类型或String类型时,属于深复制,即原数组与新数组的元素不会相互影响
-
当数组为多维数组,或一维数组中的元素为引用类型时,属于浅复制,原数组与新数组的元素引用指向同一个对象
这里说的影响,是两个数组复制后对应的元素,并不一定是下标对应
String的特殊是因为它的不可变性
多维数组实际上可以理解为一维数组中的每个元素又是一个一维或多维数组的首地址,所以复制时的效果与对象数组的结果是一样的
这个是系统提供的拷贝方式,这个方法不是用java语言写的,因为native,而是底层用c或者c++实现的,因而速度会比较快。
/** * System.arraycopy的方法原型 * @param src 要复制的源数组 * @param srcPos 源数组要复制的起始位置(从0开始) * @param dest 要复制的目标数组 * @param destPos 目标数组的起始位置(从0开始不可长度不可超过目标数组长度) * @param length 要复制的长度(长度不可超过目标数组长度-destPos) */ public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
int[] arrayA = {1, 2};//1 2 int[] arrayB = new int[6]; System.arraycopy(arrayA, 0,arrayB,0,2);//1 2 0 0 0 0
-
-
Arrays.copyOf(不需要准备好目标数组,并分配长度)
本质上使用了System.arraycopy
copyOf方法是复制数组至指定长度
不够会自动填充
/** * @Description 复制指定的数组, 如有必要用 null 截取或填充,以使副本具有指定的长度 * 对于所有在原数组和副本中都有效的索引,这两个数组相同索引处将包含相同的值 * 对于在副本中有效而在原数组无效的所有索引,副本将填充 null,当且仅当指定长度大于原数组的长度时,这些索引存在 * 返回的数组属于 newType 类 * @param original 要复制的数组 * @param newLength 副本的长度 * @param newType 副本的类 * * @return T 原数组的副本,截取或用 null 填充以获得指定的长度 * @throws NegativeArraySizeException 如果 newLength 为负 * @throws NullPointerException 如果 original 为 null * @throws ArrayStoreException 如果从 original 中复制的元素不属于存储在 newType 类数组中的运行时类型 * @since 1.6 */ public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { 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; }
int[] arrayA = {1, 2}; int[] arrayB = Arrays.copyOf(arrayA,4);//1 2 0 0
-
Arrays.copyOfRange(可以选择开始复制位置,结束位置为目标数组位置)
本质上使用了System.arraycopy
copyOfRange方法是将指定数组的指定长度复制到一个新的数组
可以选择指定开始位置复制,结束位置按目标数组来
原数组不够到结束,会自动填充
copyOfRange只需要源数组就就可以了,通过返回值,就能够得到目标数组了。
除此之外,需要注意的是 copyOfRange 的第3个参数,表示源数组的结束位置,是取不到的。/** * * @param original 源数组 * @param from 表示开始位置(取得到) * @param to 表示结束位置(取不到) * @return 新数组 */ public static byte[] copyOfRange(byte[] original, int from, int to) { int newLength = to - from; if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); byte[] copy = new byte[newLength]; System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); return copy; }
int[] arrayA = {1, 2};//1 2 int[] arrayB = new int[3]; System.arraycopy(arrayA, 0,arrayB,0,2);//1 2 0 int[] arrayC = Arrays.copyOf(arrayA, 6);//1 2 0 0 0 0 int[] arrayD = Arrays.copyOfRange(arrayA, 1, 6);//2 0 0 0 0