java數組拷貝主要有四種方法,分別是循環賦值,System.arraycopy(),Arrays.copyOf()(或者Arrays.copyOfRange)和clone()方法。下面分別介紹一下這幾種拷貝。
一、循環拷貝(速度相對比較慢)
循環拷貝其實沒什么好說的啦,就是用一個for循環進行元素的逐個拷貝,進行深拷貝或者淺復制這個大家可以自己把握。
二、System.arraycopy(淺拷貝)
這個是系統提供的拷貝方式,也是我們推薦使用的拷貝方式,它是淺拷貝,也就是說對於非基本類型而言,它拷貝的是對象的引用,而不是去新建一個新的對象。通過它的代碼我們可以看到,這個方法不是用java語言寫的,而是底層用c或者c++實現的,因而速度會比較快。
1 public static native void arraycopy 2 (Object src, int srcPos,Object dest, int destPos,int length);
通過源代碼我們可以看到,關鍵字native說明它不是用java語言寫的,而是調用其他語言的代碼。
1、先來看看基本數據類型的System.arraycopy() 方法拷貝:
1 import java.util.Arrays; 2 public class TestDemo { 3 public static void main(String[] args) { 4 5 int[] array1 = new int[]{1,2,8,7,6}; 6 int[] array2 = new int[array1.length]; 7 System.arraycopy(array1, 0, array2, 0, array1.length); 8 9 System.out.println("array1 = " + Arrays.toString(array1)); 10 System.out.println("array2 = " + Arrays.toString(array2)); 11 System.out.println("========================="); 12 13 array2[0] = 100; 14 System.out.println("array1 = " + Arrays.toString(array1)); 15 System.out.println("array2 = " + Arrays.toString(array2)); 16 17 } 18 }
這段程序的結果是:
array1 = [1, 2, 8, 7, 6] array2 = [1, 2, 8, 7, 6] ========================= array1 = [1, 2, 8, 7, 6] array2 = [100, 2, 8, 7, 6]
由結果可以看出,當對復制數組的某個元素進行改變時,並不影響被復制數組對應元素,即對於基本數據類型來說System.arraycopy() 方法是深拷貝。
2、同樣的,看一下當對象不是基本數據類型,而是引用數據類型時的情況
看以下例子:
1 class TestArray{ 2 private int val = 10; 3 public void setVal(int val){ 4 this.val = val; 5 } 6 public int getVal(){ 7 return this.val; 8 } 9 } 10 11 public class TestDemo { 12 /**數組輸出方法 */ 13 public static void printArray(TestArray[] array){ 14 for(int i = 0;i < array.length;i++){ 15 System.out.print(array[i].getVal()+" "); 16 } 17 System.out.println(); 18 } 19 20 public static void main(String[] args) { 21 TestArray[] array1 = new TestArray[3]; 22 // 數組引用賦值 23 for (int i = 0; i < array1.length; i++){ 24 array1[i] = new TestArray(); 25 } 26 27 TestArray[] array2 = new TestArray[array1.length]; 28 // 數組System.arraycopy()方法復制 29 System.arraycopy(array1,0,array2,0,array1.length); 30 31 printArray(array1); 32 printArray(array2); 33 System.out.println("=========="); 34 35 array2[0].setVal(100);; 36 printArray(array1); 37 printArray(array2); 38 } 39 }
這段程序的結果是:
10 10 10 10 10 10 ========== 100 10 10 100 10 10
由結果可以看出,當對復制數組的某個元素進行改變時,被復制數組對應元素也隨之改變,即對於引用數據類型來說 System.arraycopy() 方法是淺拷貝。
三、Arrays.copyOf(淺拷貝)
這個方法也是淺拷貝,為什么呢?我們看一下它的源代碼就知道了。
1 public static byte[] copyOfRange(byte[] original, int from, int to) { 2 int newLength = to - from; 3 if (newLength < 0) 4 throw new IllegalArgumentException(from + " > " + to); 5 byte[] copy = new byte[newLength]; 6 System.arraycopy(original, from, copy, 0,Math.min(original.length - from, newLength)); 7 return copy; 8 }
可以看到其實Arrays.copyOf()方法在底層是調用了 System.arraycopy() 方法來實現復制,即可以把Arrays.copyOf() 方法看作是 System.arraycopy() 方法的衍生方法,故它的執行機理與 System.arraycopy() 方法相同。 所以 Arrays.copyOf() 方法對於基本數據類型來說是深拷貝,對引用類型來說是淺拷貝。
四、對象拷貝(Object.clone)
clone()比較特殊,對於對象而言,它是深拷貝,但是對於數組而言,它是淺拷貝。 首先講一下對象的拷貝,它是深拷貝,大家可以用對象去測試一下。下面我們看一下它的源代碼:
1 protected native Object clone() throws CloneNotSupportedException;
這里也有native關鍵字,所以也是底層的c語言實現的。 還要注意的是,這里修飾符是protected,也就是說,我們創建了一個Object類以后,是不能直接調用這個clone()方法的,因為protected關鍵字只允許同一個包內的類和它的子類調用,所以我們聲明一個object類時,肯定不是同一個包內,所以就不能去調用它。 要調用這個方法,就需要我們寫一個類,然后聲明實現cloneable接口就好了,不需要去顯示地聲明繼承於object,因為java中的類如果不顯示說明父類的話,默認父類就是object。然后我們繼承這個方法:
1 @Override 2 public Object clone() throws CloneNotSupportedException { 3 // TODO Auto-generated method stub 4 return super.clone(); 5 }
這里需要是,為了能夠在不同包內去調用這個方法,我們需要把這個權限升級為public。現在我們就可以調用這個類的clone()方法去拷貝我們的類了。
五、數組拷貝
對於數組而言,它不是簡單的將引用賦值為另外一個數組引用,而是創建一個新的數組。但是我們知道,對於數組本身而言,它它的元素是對象的時候,本來數組每個元素中保存的就是對象的引用,所以,拷貝過來的數組自然而言也是對象的引用,所以對於數組對象元素而言,它又是淺拷貝。我們用以下代碼驗證一下:
1 class Aby implements Cloneable{ 2 public int i; 3 public Aby(int i) { 4 this.i = i; 5 } 6 @Override 7 public Object clone() throws CloneNotSupportedException { 8 // TODO Auto-generated method stub 9 return super.clone(); 10 } 11 } 12 public class Solution { 13 14 public static void main(String[] args) throws CloneNotSupportedException { 15 Aby aby1 = new Aby(1); 16 Aby aby2 = (Aby) aby1.clone(); 17 aby1.i = 2; 18 System.out.println(aby1.i); //2 19 System.out.println(aby2.i); //1 20 21 Aby[] arr = {aby1,aby2}; 22 23 Aby[] arr2 = arr.clone(); 24 arr2[0].i = 3; 25 System.out.println(arr[0].i); //3 26 System.out.println(arr2[0].i); //3 27 } 28 }