瞭解陣列是物件,你就應該知道,以下這個並非陣列複製:
int[] scores1 = {88, 81, 74, 68, 78, 76, 77, 85, 95, 93};
int[] scores2 = scores1;
這個程式片段,只不過是將scores1
參考的陣列物件,也給scores2
參考。如果你要作陣列複製,基本作法是另行建立新陣列。例如:
int[] scores1 = {88, 81, 74, 68, 78, 76, 77, 85, 95, 93};
int[] scores2 = new int[scores1.length];
for(int i = 0; i < scores1.length; i++) {
scores2[i] = scores1[i];
}
在這個程式片段中,建立一個長度與scores1
相同的新陣列,再逐一走訪scores1
每個索引元素,並指定給scores2
對應的索引位置。事實上,不用自行使用迴圈作值的複製,而可以使用System.arraycopy()
方法,這個方法會使用原生方式複製每個索引元素,比自行使用迴圈來得快:
int[] scores1 = {88, 81, 74, 68, 78, 76, 77, 85, 95, 93};
int[] scores2 = new int[scores1.length];
System.arraycopy(scores1, 0, scores2, 0, scores1.length);
System.arraycopy()
的五個參數分別是來源陣列、來源起始索引、目的陣列、目的起始索引、複製長度。如果使用JDK6以上,還有個更方便的Arrays.copyOf()
方法,你不用另行建立新陣列,Arrays.copyOf()
會幫你建立。例如:
package cc.openhome;
import java.util.Arrays;
public class CopyArray {
public static void main(String[] args) {
int[] scores1 = {88, 81, 74, 68, 78, 76, 77, 85, 95, 93};
int[] scores2 = Arrays.copyOf(scores1, scores1.length);
for(int score : scores2) {
System.out.printf("%3d", score);
}
System.out.println();
scores2[0] = 99;
// 不影響score1參考的陣列物件
for(int score : scores1) {
System.out.printf("%3d", score);
}
}
}
執行結果如下所示:
88 81 74 68 78 76 77 85 95 93
在Java中,陣列一旦建立,長度就固定了。如果你事先建立的陣列長度不夠怎麼辦?那就只好建立新陣列,將原陣列內容複製至新陣列。例如:
int[] scores1 = {88, 81, 74, 68, 78, 76, 77, 85, 95, 93};
int[] scores2 = Arrays.copyOf(scores1, scores1.length * 2);
for(int score : scores2) {
System.out.printf("%3d", score);
}
Arrays.copyOf()
的第二個參數,實際上就是指定建立的新陣列長度。上面這個程式片段建立的新陣列是20,執行結果顯示原scores1
複製過去的88到93的元素,而後顯示10個預設值0。以上都是示範基本型態陣列,對於類別型態宣告的陣列則要注意參考的行為。直接來看個範例:
package cc.openhome;
class Clothes {
String color;
char size;
Clothes(String color, char size) {
this.color = color;
this.size = size;
}
}
public class ShallowCopy {
public static void main(String[] args) {
Clothes[] c1 = {new Clothes("red", 'L'), new Clothes("blue", 'M')};
Clothes[] c2 = new Clothes[c1.length];
for(int i = 0; i < c1.length; i++) {
c2[i] = c1[i];
}
c1[0].color = "yellow";
System.out.println(c2[0].color);
}
}
這個程式的執行結果會是yellow,這是怎麼回事?原因在於迴圈執行完畢後,用圖來表示的話就是:
實際上迴圈中僅將
c1
每個索引處所參考的物件,也給c2
每個索引來參考,並沒有實際複製出Clothes
物件,術語上來說,這叫作複製參考,或稱這個行為是淺層複製(Shallow copy)。無論是System.arraycopy()
或Arrays.copyOf()
,用在類別型態宣告的陣列時,都是執行淺層複製。如果真的要連同物件一同複製,你得自行實作,因為基本上只有自己才知道,每個物件複製時,有哪些屬性必須複製。例如:package cc.openhome;
class Clothes2 {
String color;
char size;
Clothes2(String color, char size) {
this.color = color;
this.size = size;
}
}
public class DeepCopy {
public static void main(String[] args) {
Clothes2[] c1 = {new Clothes2("red", 'L'), new Clothes2("blue", 'M')};
Clothes2[] c2 = new Clothes2[c1.length];
for(int i = 0; i < c1.length; i++) {
Clothes2 c = new Clothes2(c1[i].color, c1[i].size);
c2[i] = c;
}
c1[0].color = "yellow";
System.out.println(c2[0].color);
}
}
這個範例執行所謂深層複製(Deep copy)行為,也就是實際上c1每個索引參考的物件會被複製,分別指定給
c2
每個索引,結果就是顯示red。在迴圈執行完畢後,用圖來表示參考與物件之間的關係會是: