Javaの道 Javaに関する
 ニュースJava基本Servlet・JSPオープンソースFAQ掲示板
Javaの道 > Java基本 > 配列 −2.配列のコピー列
更新日:2005/7/17
配列−2.配列のコピー
このページでは配列に用意されている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). int型の配列intArrayを宣言・生成します。
(2). forループの条件式で配列サイズを超えない限り(配列の最後の要素まで)forループの実行文を実行する意味の条件式を記載します。
(3). 変数i×10の値を順番に配列intArrayの中に代入します。
(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). コピー元の配列charArray1を宣言・生成します。
(2). コピー先の配列charArray2をcharArray1と同じサイズで宣言・生成します。
(3). forループを使用し、charArray1の最後の要素まで順番にcharArray2にデータの代入を行います。
(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). コピー元の配列charArray1を宣言・生成します。
(2). cloneメソッドを使用し、コピー先の配列charArray2へコピーを行います。cloneメソッドは戻り型としてObject型を返すため、char型配列でキャストします。
(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). コピー元の配列FromIntを宣言・生成します。
(2). コピー先の配列ToIntを宣言・生成します。
(3). arraycopyメソッドを使用し、配列のコピーを行います。ここではFromInt配列のインデックス番号1から5インデックス分をToInt配列のインデックス番号3から順番にコピーをすることを意味します。
(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). シャローコピーのコピー元の配列FromShallowを宣言・生成し、その後各配列の要素にStringBufferオブジェクトの生成を行っています。
(2). ディープコピーのコピー元の配列FromDeepを宣言・生成し、その後各配列の要素にStringBufferオブジェクトの生成を行っています。
(3). FromShallowと同じサイズのシャローコピーのコピー先の配列ToShallowを宣言・生成します。
(4). FromDeepと同じサイズのディープコピーのコピー先の配列ToDeepを宣言・生成します。
(5). cloneメソッドを使用し、FromShallowの内容をToShallowにコピーします。
(6). forループを使用し、FromDeepの内容をToDeepにコピーします。
(7). StringBufferクラスのメソッドreplaceを使用し、ToShallowの内容をSundayからMondayに変更しています。
(8). StringBufferクラスのメソッドreplaceを使用し、ToDeepの内容をSundayからMondayに変更しています。
(9). コピー元配列FromShallowに影響がないか、printlnメソッドで確認を行います。
(10). コピー元配列ToShallowに影響がないか、printlnメソッドで確認を行います。
【実行結果5】
D:\JAVA>javac ExArray5.java

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

D:\JAVA>
配列
1.配列の基本
2.配列のコピー
3.2次元配列



このページのトップへ
 ニュースJava基本Servlet・JSPオープンソースFAQ掲示板
Javaの道_CopyrightJavaの道