Javaに関する様々な情報をご紹介します。

2配列のコピー

Javaに関する様々な情報をご紹介します。

配列のコピー

このページでは配列に用意されているlength属性及び、配列のコピーの方法についての説明を行います。

length

length属性は配列すべてに用意されている配列サイズを返す属性です。 length( )と言うものもありますが、これはStringオブジェクトやStringBufferオブジェクトの文字列数を返すメソッドであり、配列の属性lengthとは異なります。 length属性はしばしばforループ内で配列に何らかの処理を行いたい時などに使用します。

例1

public class ExArray {
    public static void main(String[] args) {
        int[] intArray = new int[10];   //(1)
        for (int i = 0; i < intArray.length; i++) {   //(2)
            intArray[i] = i * 10;   //(3)
            System.out.println(intArray[i]);   //(4)
        }
    }
}

解説1

  1. (1)int型の配列intArrayを宣言・生成します。
  2. (2)forループの条件式で配列サイズを超えない限り(配列の最後の要素まで)forループの実行文を実行する意味の条件式を記載します。
  3. (3)変数i×10の値を順番に配列intArrayの中に代入します。
  4. (4)printlnメソッドで配列内に代入された値の表示を行います。

実行結果1

D:\JAVA>javac ExArray.java

D:\JAVA>java ExArray
0
10
20
30
40
50
60
70
80
90

D:\JAVA>

配列のコピー

配列を他の配列へコピーしたいといったことがあります。ここでは配列のコピーの仕方をforループを使用した場合、cloneメソッドを使用した場合、arraycopyメソッドを使用した場合の3つに分け、それぞれ説明します。

forループを使用した場合

forループを使用し配列のコピーを行う場合は配列のlength属性を使用します。

例2

public class ExArray2 {
    public static void main(String[] args) {
        char[] charArray1 = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; //(1)
        char[] charArray2 = new char[charArray1.length];   //(2)
    
        for (int i = 0; i < charArray1.length; i++) {   //(3)
            charArray2[i] = charArray1[i];
        }
    
        for (int i = 0; i < charArray2.length; i++) {   //(4)
            System.out.println(charArray2[i]);
        }
    }
}

解説2

  1. (1)コピー元の配列charArray1を宣言・生成します。
  2. (2)コピー先の配列charArray2をcharArray1と同じサイズで宣言・生成します。
  3. (3)forループを使用し、charArray1の最後の要素まで順番にcharArray2にデータの代入を行います。
  4. (4)コピーが正しく行われているか、charArray2の配列のデータの内容を順番に表示します。

実行結果2

D:\JAVA>javac ExArray2.java

D:\JAVA>java ExArray2
A
B
C
D
E
F
G

D:\JAVA>

cloneメソッドを使用した場合

cloneメソッドを使用することによりある配列を別の配列へコピーすることができます。
cloneメソッドはオブジェクトのコピーを行うメソッドです。

例3

public class ExArray3 {
    public static void main(String[] args) {
        char[] charArray1 = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; //(1)
        char[] charArray2 = (char[])charArray1.clone();   //(2)

        for (int i = 0; i < charArray2.length; i++) {   //(3)
            System.out.println(charArray2[i]);
        }
    }
}

解説3

  1. (1)コピー元の配列charArray1を宣言・生成します。
  2. (2)cloneメソッドを使用し、コピー先の配列charArray2へコピーを行います。cloneメソッドは戻り型としてObject型を返すため、char型配列でキャストします。
  3. (3)コピーが正しく行われているか、charArray2の配列のデータの内容を順番に表示します。

実行結果3

D:\JAVA>javac ExArray3.java

D:\JAVA>java ExArray3
A
B
C
D
E
F
G

D:\JAVA>

arraycopyメソッドを使用した場合

arraycopyメソッドを使用することにより配列の範囲を指定して、別の配列へコピーすることができます。arraycopyメソッドはSYSTEMクラスで用意されているメソッドの一つです。

例4

public class ExArray4 {
    public static void main(String[] args) {
        int[] FromInt = {1, 2, 3, 4, 5, 6, 7};   //(1)
        int[] ToInt = new int[10];   //(2)
        System.arraycopy(FromInt, 1, ToInt, 3, 5);   //(3)
    
        for (int i = 0; i < ToInt.length; i++) {   //(4)
            System.out.println(ToInt[i]);
        }
    }
}

解説4

  1. (1)コピー元の配列FromIntを宣言・生成します。
  2. (2)コピー先の配列ToIntを宣言・生成します。
  3. (3)arraycopyメソッドを使用し、配列のコピーを行います。ここではFromInt配列のインデックス番号1から5インデックス分をToInt配列のインデックス番号3から順番にコピーをすることを意味します。
  4. (4)コピーが正しく行われているか、ToInt配列のデータの内容を順番に表示します。

実行結果4

D:\JAVA>javac ExArray4.java

D:\JAVA>java ExArray4
0
0   #データがコピーされていない個所は初期値である0が表示されます。
0
2   #FromInt配列のインデックス番号1のデータがコピーされています。
3
4
5
6
0
0

D:\JAVA>

配列のコピーの注意点

ここでは配列のコピーを行う際の注意点について説明します。Javaではオブジェクトのコピーを行う際、シャローコピー(shallowコピー)ディープコピー(deepコピー)という2つの方式を意識する必要があります。
シャローコピーとはコピー先のオブジェクトに対し、そのオブジェクトの参照情報のみ複写する方法です。つまりコピー元、コピー先とも同じオブジェクトを参照しています。ディープコピーとはコピー先のオブジェクトに対し、参照情報だけでなくオブジェクトの実体も複写する方法です。シャローコピーを行った場合は、コピー先のオブジェクトの値を変更するとコピー元のオブジェクトの値も変更されます。

配列もオブジェクトですからシャローコピーとディープコピーを考慮する必要があります。cloneメソッド、arraycopyメソッドを使用した場合はシャローコピーとなります。forループを使用した場合はループ内の実装方法の違い(新たなインスタンスを生成するか(ディープ)、代入演算子=によりコピーを行うか(シャロー)。)によりディープコピーにもなりますし、シャローコピーにもなります。どちらの方法を使用するかはケースにより異なります。

シャローコピー

シャローコピー

ディープコピー

ディープコピー

例5

forループでディープコピーした場合とcloneメソッドをシャローコピーした場合のコピーを違いを比較します。

public class ExArray5 {
    public static void main(String[] args) {
        StringBuffer[] FromShallow = new StringBuffer[2];   //(1)
        FromShallow[0] = new StringBuffer("Sunday");
        FromShallow[1] = new StringBuffer("Monday");
    
        StringBuffer[] FromDeep = new StringBuffer[2];   //(2)
        FromDeep[0] = new StringBuffer("Sunday");
        FromDeep[1] = new StringBuffer("Monday");
    
        StringBuffer[] ToShallow = new StringBuffer[2];   //(3)
        StringBuffer[] ToDeep = new StringBuffer[2];   //(4)
    
        //cloneメソッドを使用し、配列のコピーを行います。
        ToShallow = (StringBuffer[])FromShallow.clone();   //(5)
    
        //forループを使用し、配列のコピーを行います。
        for (int i=0; i < FromDeep.length; i++) {   //(6)
            ToDeep[i] = new StringBuffer(FromDeep[i].toString());
        }
    
        //シャローコピー、ディープコピーが同コピー元に影響を与えるか、
        //コピー先のデータを変更しています。
        ToShallow[0] = ToShallow[0].replace(0, 3, "Mon");   //(7)
        ToDeep[0]= ToDeep[0].replace(0, 3, "Mon");   //(8)
    
        System.out.println
        ("FromShallow[0]の値Sundayは" + FromShallow[0]);   //(9)
        System.out.println
        ("FromDeep[0]の値Sundayは" + FromDeep[0]);   //(10)
    }
}

解説5

  1. (1)シャローコピーのコピー元の配列FromShallowを宣言・生成し、その後各配列の要素にStringBufferオブジェクトの生成を行っています。
  2. (2)ディープコピーのコピー元の配列FromDeepを宣言・生成し、その後各配列の要素にStringBufferオブジェクトの生成を行っています。
  3. (3)FromShallowと同じサイズのシャローコピーのコピー先の配列ToShallowを宣言・生成します。
  4. (4)FromDeepと同じサイズのディープコピーのコピー先の配列ToDeepを宣言・生成します。
  5. (5)cloneメソッドを使用し、FromShallowの内容をToShallowにコピーします。
  6. (6)forループを使用し、FromDeepの内容をToDeepにコピーします。
  7. (7)StringBufferクラスのメソッドreplaceを使用し、ToShallowの内容をSundayからMondayに変更しています。
  8. (8)StringBufferクラスのメソッドreplaceを使用し、ToDeepの内容をSundayからMondayに変更しています。
  9. (9)コピー元配列FromShallowに影響がないか、printlnメソッドで確認を行います。
  10. (10)コピー元配列ToShallowに影響がないか、printlnメソッドで確認を行います。

実行結果5

D:\JAVA>javac ExArray5.java

D:\JAVA>java ExArray5
FromShallow[0]の値SundayはMonday   #シャローコピーの方はコピー元のデータも変更されています。
FromDeep[0]の値SundayはSunday

D:\JAVA>

2配列のコピー