配列のコピーを作るメソッドにclone()がありますが、arraycopy()も同じように配列のコピーを作ります。
ただし、構文はclone()とは異なり
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
ソース配列srcの srcPos から srcPos+length-1 までの位置にある要素を、転送先の配列destの destPos から destPos+length-1 までの位置にそれぞれコピーします。
コピー対象は配列であり、配列要素は基本型及びString型、オブジェクト型ですがコピー元とコピー先の型は同一の物でなければならず、srcPos及びdestPos、lengthは正の値で、コピーされるソース配列の配列要素及び転送先配列の配列要素はそれぞれの配列サイズ内でなければいけません。
まず、配列要素が基本型の場合
int型の配列arrayOrg[]とarrayNew[]を作り、arrayOrgの先頭要素から配列要素の末尾までをarrayNewの先頭から末尾までにコピーします。
9行目で二つの配列変数の内容を比較し、配列変数が同じ配列インスタンスを指しているか否かを確認しています。
次にそれぞれの配列インスタンスの中身が同一かを確認。
その上で、19行目で新しい配列の要素の内容を変更し、その変更がコピー元の配列に影響するか確認し、影響していればシャローコピー、指定なければディープコピーと判断しています。
import java.util.*; public class IntArrayCopy { public static void main(String[] args) { int[] arrayOrg = { 10, 20 }; int[] arrayNew = new int[2]; System.arraycopy(arrayOrg, 0, arrayNew, 0, arrayOrg.length); System.out.println("arrayOrg:" + arrayOrg + " arrayNew:" + arrayNew); if (arrayOrg == arrayNew) { System.out.println("arrayOrg == arrayNew"); } else { System.out.println("arrayOrg != arrayNew"); } if (Arrays.equals(arrayOrg, arrayNew)) { System.out.println("arrayOrg[] equals arrayNew[]"); } else { System.out.println("arrayOrg[] not equals arrayNew[]"); } arrayNew[1] = 10; System.out.println("\nchange arrayNew[1] = 10"); for (int i = 0; i < arrayOrg.length; i++) { System.out.println("arrayOrg[" + i + "] = " + arrayOrg[i] + " " + "arrayNew[" + i + "] = " + arrayNew[i]); } if(arrayNew[1] == arrayOrg[1]) System.out.println("shallow copy"); else System.out.println("deep copy"); } }
実行結果は、新しい配列が指し示す配列インスタンスはコピー元の配列インスタンスとは異なりますが、配列の内容は同じ。そして、新しい配列の配列要素の内容を一部変えても、その影響はコピー元の配列には影響しない事を示しています。
従って、配列要素が基本型の場合のarraycopy()メソッドはディープコピーで新しい配列を作っています。
>java IntArrayCopy arrayOrg:[I@15db9742 arrayNew:[I@6d06d69c arrayOrg != arrayNew arrayOrg[] equals arrayNew[] change arrayNew[1] = 10 arrayOrg[0] = 10 arrayNew[0] = 10 arrayOrg[1] = 20 arrayNew[1] = 10 deep copy >
次に、配列要素がString型の場合
6行目で作成する配列をString型に変えて、同じ処理を行います。
import java.util.*; public class StrArrayCopy { public static void main(String[] args) { String[] arrayOrg = { "A", "B" }; String[] arrayNew = new String[2]; System.arraycopy(arrayOrg, 0, arrayNew, 0, arrayOrg.length); System.out.println("arrayOrg:" + arrayOrg + " arrayNew:" + arrayNew); if (arrayOrg == arrayNew) { System.out.println("arrayOrg == arrayNew"); } else { System.out.println("arrayOrg != arrayNew"); } if (Arrays.equals(arrayOrg, arrayNew)) { System.out.println("arrayOrg[] equals arrayNew[]"); } else { System.out.println("arrayOrg[] not equals arrayNew[]"); } arrayNew[1] = "A"; System.out.println("\nchange arrayNew[1] = A"); for (int i = 0; i < arrayOrg.length; i++) { System.out.println("arrayOrg[" + i + "] = " + arrayOrg[i] + " " + "arrayNew[" + i + "] = " + arrayNew[i]); } if(arrayNew[1].equals(arrayOrg[1])) System.out.println("shallow copy"); else System.out.println("deep copy"); } }
結果は同じく、新しい配列が指し示す配列インスタンスはコピー元の配列インスタンスとは異なりますが、配列の内容は同じ。そして、新しい配列の配列要素の内容を一部変えても、その影響はコピー元の配列には影響しません。
従って、配列要素がString型の場合のarraycopy()メソッドもディープコピーで新しい配列を作ります。
>>java StrArrayCopy arrayOrg:[Ljava.lang.String;@15db9742 arrayNew:[Ljava.lang.String;@6d06d69c arrayOrg != arrayNew arrayOrg[] equals arrayNew[] change arrayNew[1] = A arrayOrg[0] = A arrayNew[0] = A arrayOrg[1] = B arrayNew[1] = A deep copy >
最後に、配列要素がオブジェクト型の場合です。
5行目から8行目で作成する配列をObjArrayというオブジェクト型に変えて、同じ処理を行います。
import java.util.*; public class ObjArrayCopy { public static void main(String[] args) { ObjArray[] arrayOrg = { new ObjArray(10), new ObjArray(20) }; ObjArray[ ] arrayNew = new ObjArray[2]; System.arraycopy(arrayOrg, 0, arrayNew, 0, arrayOrg.length); System.out.println("arrayOrg:" + arrayOrg + " arrayNew:" + arrayNew); if (arrayOrg == arrayNew) { System.out.println("arrayOrg == arrayNew"); } else { System.out.println("arrayOrg != arrayNew"); } if (Arrays.equals(arrayOrg, arrayNew)) { System.out.println("arrayOrg[] equals arrayNew[]"); } else { System.out.println("arrayOrg[] not equals arrayNew[]"); } arrayNew[1].num = 10; System.out.println("\nchange arrayNew[1].num = 10"); for (int i = 0; i < arrayOrg.length; i++) { System.out.println("arrayOrg[" + i + "] = " + arrayOrg[i] + " " + "arrayNew[" + i + "] = " + arrayNew[i]); } if(arrayNew[1].equals(arrayOrg[1])) System.out.println("shallow copy"); else System.out.println("deep copy"); } } class ObjArray { int num; ObjArray(int num) { this.num = num; } }
この場合も、新しい配列が指し示す配列インスタンスはコピー元の配列インスタンスとは異なりますが、配列の内容は同じ。しかし、新しい配列の配列要素の内容を一部変えると、その影響はコピー元の配列には影響してしまいます。
つまり、配列要素がオブジェクト型の場合のarraycopy()メソッドは配列インスタンスをディープコピーで作成しますが、各配列要素が指し示すオブジェクトはシャロ―コピーで作成します。
>java ObjArrayCopy arrayOrg:[LObjArray;@15db9742 arrayNew:[LObjArray;@6d06d69c arrayOrg != arrayNew arrayOrg[] equals arrayNew[] change arrayNew[1].num = 10 arrayOrg[0] = ObjArray@7852e922 arrayNew[0] = ObjArray@7852e922 arrayOrg[1] = ObjArray@4e25154f arrayNew[1] = ObjArray@4e25154f shallow copy >
この様に、同じarraycopy()メソッドでもコピーする配列の内容によりコピーによって作られる配列の作りが変わるので、注意が必要です。
さて、以上の事からarraycopy()はclone()と同じ配列のコピーが出来る事が分かりましたが、何か違いはないのでしょうか。
それはarraycopy()がコピーの開始位置やコピーする配列要素数を指定できるだけでなく、ソース配列srcと転送先の配列destに同じ配列オブジェクトを指定できる事がarraycopy()の特徴です。
import java.util.*; public class ObjArrayCopyInner { public static void main(String[] args) { ObjArray[] arrayOrg = { new ObjArray(10), new ObjArray(20), new ObjArray(30) }; System.out.println("arrayOrg before arraycopy:" + arrayOrg); for (int i = 0; i < arrayOrg.length; i++) { System.out.println("arrayOrg[" + i + "] = " + arrayOrg[i].num); } System.arraycopy(arrayOrg, 0, arrayOrg, 1, 2); System.out.println("arrayOrg after arraycopy:" + arrayOrg); for (int i = 0; i < arrayOrg.length; i++) { System.out.println("arrayOrg[" + i + "] = " + arrayOrg[i].num); } } } class ObjArray { int num; ObjArray(int num) { this.num = num; } }
>java ObjArrayCopyInner arrayOrg before arraycopy:[LObjArray;@15db9742 arrayOrg[0] = 10 arrayOrg[1] = 20 arrayOrg[2] = 30 arrayOrg after arraycopy:[LObjArray;@15db9742 arrayOrg[0] = 10 arrayOrg[1] = 10 arrayOrg[2] = 20 >