java 数组一共有四种拷贝方式:for循环、copyof/copyOfRange/arraycopy/clone。本文为大家介绍这四种。
深拷贝与浅拷贝的区别
假设现在有原数组A以及拷贝后的数组B,若是改变A中的某一个值,B数组随之相应的发生变化的拷贝方式称为浅拷贝,反之B数组不受影响,则称为深拷贝;
简单总结一下两者的概念:
深拷贝:拷贝后,修改原数组,不会影响到新数组;
浅拷贝:拷贝后,修改原数组,新数组也会相应的发生改变;
1. for循环进行拷贝
拷贝数值类型
当数组中存放的元素为基本数据类型时,此时发生的是深拷贝;
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 | //1. for循环拷贝 (拷贝数值类型) ---深拷贝 public static void main(String[] args) { int [] A = { 1 , 2 , 3 , 4 , 5 }; int [] B = new int [A.length]; for ( int i = 0 ; i < A.length; i++) { B[i] = A[i]; } System.out.println( "A : " + Arrays.toString(A)); //A : [1, 2, 3, 4, 5] System.out.println( "B : " + Arrays.toString(B)); //B : [1, 2, 3, 4, 5] System.out.println( "===========修改后===========" ); A[ 0 ] = 100 ; System.out.println( "A : " + Arrays.toString(A)); //A : [100, 2, 3, 4, 5] System.out.println( "B : " + Arrays.toString(B)); //B : [1, 2, 3, 4, 5] } //打印对象数组的方法 public static void show(Num[] arrays) { for ( int i = 0 ; i < arrays.length; i++) { System.out.print(arrays[i].getVal() + " " ); } System.out.println(); } class Num{ public int val = 0 ; public Num( int val) { this .val = val; } public int getVal() { return val; } public void setVal( int val) { this .val = val; } } |
拷贝引用类型
当数组中存放的元素为引用数据类型时,此时发生的是浅拷贝;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //1. for循环拷贝 (拷贝引用数据类型) ---浅拷贝 public static void main(String[] args) { Num[] A = new Num[ 4 ]; A[ 0 ] = new Num( 1 ); A[ 1 ] = new Num( 2 ); A[ 2 ] = new Num( 3 ); A[ 3 ] = new Num( 4 ); Num[] B = new Num[ 4 ]; for ( int i = 0 ; i < A.length; i++) { B[i] = A[i]; } show(A); //1 2 3 4 show(B); //1 2 3 4 System.out.println( "===========修改后===========" ); A[ 0 ].setVal( 100 ); show(A); //100 2 3 4 show(B); //100 2 3 4 } |
2. copyof / copyOfRange
拷贝数值类型
当数组中存放的元素为基本数据类型时,此时发生的是深拷贝;
Arrays.copy(原数组,自定义新数组长度);
Arrays.copyOfRange(原数组,from,to);
注意拷贝截取的范围是左闭右开的[from,to)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //2. copy / copyOfRange (拷贝数值类型) ---深拷贝 public static void main(String[] args) { int [] A = { 1 , 2 , 3 , 4 , 5 }; int [] B = Arrays.copyOf(A,A.length); int [] C = Arrays.copyOfRange(A, 1 , 3 ); System.out.println( "A : " + Arrays.toString(A)); //A : [1, 2, 3, 4, 5] System.out.println( "B : " + Arrays.toString(B)); //B : [1, 2, 3, 4, 5] System.out.println( "C : " + Arrays.toString(C)); //C : [2, 3] System.out.println( "===========修改后===========" ); A[ 0 ] = 100 ; System.out.println( "A : " + Arrays.toString(A)); //A : [100, 2, 3, 4, 5] System.out.println( "B : " + Arrays.toString(B)); //B : [1, 2, 3, 4, 5] System.out.println( "C : " + Arrays.toString(C)); //C : [2, 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 | //2. copy / copyOfRange (拷贝引用类型) ---浅拷贝 public static void main(String[] args) { Num[] A = new Num[ 4 ]; A[ 0 ] = new Num( 1 ); A[ 1 ] = new Num( 2 ); A[ 2 ] = new Num( 3 ); A[ 3 ] = new Num( 4 ); Num[] B = Arrays.copyOf(A,A.length); show(A); //1 2 3 4 show(B); //1 2 3 4 System.out.println( "===========修改后===========" ); A[ 0 ].setVal( 100 ); show(A); //100 2 3 4 show(B); //100 2 3 4 } class Num{ public int val = 0 ; public Num( int val) { this .val = val; } public int getVal() { return val; } public void setVal( int val) { this .val = val; } } |
3. arraycopy
拷贝数值类型
当数组中存放的元素为基本数据类型时,此时发生的是深拷贝;
System.arraycopy(src, srcPos dest, destPos, length);
其中各个参数分别表示 如下:
- src :源数组
- srcPos:源数组要复制的起始位置
- dest:目标数组
- destPos:目标数组复制的起始位置
- length:复制的长度
所以srcPos和destPos都为0,且length为源数组长度时,表示完完整整的拷贝过来了;那么截取范围拷贝也举个例子,下面的代码中srcPos = 1,destPos = 2,length = 2,表示从A数组下标为1的位置开始截取2个元素,放到B数组中下标为2的位置作为起始位置,再对比一下输出看看。
1 2 3 4 5 6 7 8 9 10 11 12 13 | //3. arraycopy (拷贝数值类型) ---深拷贝 public static void main(String[] args) { int [] A = { 1 , 2 , 3 , 4 , 5 }; int [] B = new int [A.length]; //System.arraycopy(A,0,B,0,A.length); System.arraycopy(A, 1 ,B, 2 , 2 ); System.out.println( "A : " + Arrays.toString(A)); //A : [1, 2, 3, 4, 5] System.out.println( "B : " + Arrays.toString(B)); //B : [0, 0, 2, 3, 0] System.out.println( "===========修改后===========" ); A[ 0 ] = 100 ; System.out.println( "A : " + Arrays.toString(A)); //A : [100, 2, 3, 4, 5] System.out.println( "B : " + Arrays.toString(B)); //B : [0, 0, 2, 3, 0] } |
拷贝引用类型
当数组中存放的元素为类的对象时,此时发生的是浅拷贝;
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 | //3. arraycopy (拷贝引用类型) ---浅拷贝 public static void main(String[] args) { Num[] A = new Num[ 4 ]; A[ 0 ] = new Num( 1 ); A[ 1 ] = new Num( 2 ); A[ 2 ] = new Num( 3 ); A[ 3 ] = new Num( 4 ); Num[] B = new Num[ 4 ]; System.arraycopy(A, 0 ,B, 0 ,A.length); show(A); //1 2 3 4 show(B); //1 2 3 4 System.out.println( "===========修改后===========" ); A[ 0 ].setVal( 100 ); show(A); //100 2 3 4 show(B); //100 2 3 4 } class Num{ public int val = 0 ; public Num( int val) { this .val = val; } public int getVal() { return val; } public void setVal( int val) { this .val = val; } } |
4. clone
拷贝数值类型
当数组中存放的元素为基本数据类型时,此时发生的是深拷贝;
1 2 3 4 5 6 7 8 9 10 11 | //4. clone (拷贝数值类型) ---深拷贝 public static void main(String[] args) { int [] A = { 1 , 2 , 3 , 4 , 5 }; int [] B = A.clone(); System.out.println( "A : " + Arrays.toString(A)); //A : [1, 2, 3, 4, 5] System.out.println( "B : " + Arrays.toString(B)); //B : [1, 2, 3, 4, 5] System.out.println( "===========修改后===========" ); A[ 0 ] = 100 ; System.out.println( "A : " + Arrays.toString(A)); //A : [100, 2, 3, 4, 5] System.out.println( "B : " + Arrays.toString(B)); //B : [1, 2, 3, 4, 5] } |
拷贝引用类型
当数组中存放的元素为类的对象时,此时发生的是浅拷贝;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //4. clone (拷贝引用类型) ---浅拷贝 public static void main(String[] args) { Num[] A = new Num[ 4 ]; A[ 0 ] = new Num( 1 ); A[ 1 ] = new Num( 2 ); A[ 2 ] = new Num( 3 ); A[ 3 ] = new Num( 4 ); Num[] B = A.clone(); show(A); //1 2 3 4 show(B); //1 2 3 4 System.out.println( "===========修改后===========" ); A[ 0 ].setVal( 100 ); show(A); //100 2 3 4 show(B); //100 2 3 4 } |
5. 总结
拷贝方式 | 数值类型 | 引用类型 | 推荐使用 |
---|
for循环 | 深拷贝 | 浅拷贝 | |
copyof | 深拷贝 | 浅拷贝 | √ |
arraycopy | 深拷贝 | 浅拷贝 | √ |
clone | 深拷贝 | 浅拷贝 | |
由于arraycopy底层是C++写的,所以速度快,更多的是使用这个方法。
注意:本文中所有的引用数据类型都是以类的对象为例,使用的是对象数组,我们也知道引用类型包括类,接口,字符串等等。但是需要注意字符串是新的变量,所以如果是连个字符串数组进行拷贝,即使他们是引用类型,但是每次都会创建了一个字符串数组对象, 因此, 修改原数组, 不会影响到新数组,即深拷贝。