この記事では、浅いコピー(ShallowCopy:シャローコピー)と、深いコピー(DeepCopy:ディープコピー)について解説していきます。
配列を復習するには以下の記事がおすすめです。
シャローコピーは、”参照情報”のみをコピーする方法です。
そのため、コピー元とコピー先のオブジェクトはメモリー上の同じデータを参照しています。
配列をコピーする際に=
演算子を用いるとシャローコピーになります。
Java
//コピー元の配列を生成
int[] original = {10,20,30,40,50};
//違う配列へコピー。
int[] replica = original;
//3番目の要素を500に書き換える。
replica[2] = 500;
//original配列の中身を出力。
System.out.println("original配列の中身を出力");
Arrays.stream(original).forEach(i -> System.out.print(i +" "));
System.out.println(System.getProperty("line.separator"));
//replica配列の中身を出力。
System.out.println("replica配列の中身を出力");
Arrays.stream(replica).forEach(i -> System.out.print(i +" "));
実行結果
original配列の中身を出力
10 20 500 40 50
replica配列の中身を出力
10 20 500 40 50
配列内にオブジェクトがある場合はArrays.copyOf
で生成した場合でも、シャローコピーになってしまいます。(もちろん、=
演算子でコピーしてもシャローコピーとなってしまいます。)
Java
//コピー元の配列を生成
Axis[] original = {new Axis(10,20), new Axis(30,40)};
//違う配列へコピー。
Axis[] replica = Arrays.copyOf(original, original.length);
//書き換え前の値を出力。
System.out.println("前:" + original[0].x);
System.out.println("前:" + replica[0].x);
//値を書き換える。
replica[0].x=555;
//書き換え後の値を出力。
System.out.println("後:" + original[0].x);
System.out.println("後:" + replica[0].x);
実行結果
前:10
前:10
後:555
後:555
ディープコピーは、メモリ上のデータ(インスタンス)をコピーする方法です。
コピー元とコピー先のオブジェクトは、メモリ上の別々のデータを参照していることになります。
プリミティブ型からなる配列をコピーする際にArrays.copyOf
を用いるとディープコピーになります。
Java
//コピー元の配列を生成
int[] original = {10,20,30,40,50};
//違う配列へコピー。
int[] replica = Arrays.copyOf(original, original.length);
//3番目の要素を500に書き換える。
replica[2] = 500;
//original配列の中身を出力。
System.out.println("original配列の中身を出力");
Arrays.stream(original).forEach(i -> System.out.print(i +" "));
System.out.println(System.getProperty("line.separator"));
//replica配列の中身を出力。
System.out.println("replica配列の中身を出力");
Arrays.stream(replica).forEach(i -> System.out.print(i +" "));
System.out.println(System.getProperty("line.separator"));
実行結果
original配列の中身を出力
10 20 30 40 50
replica配列の中身を出力
10 20 500 40 50
配列内がプリミティブ型の場合は、clone
メソッドを使うことでディープコピーを実現できます。
Java
//コピー元の配列を生成
int[] original = {10,20,30,40,50};
//違う配列へコピー。
int[] replica = original.clone();
//3番目の要素を500に書き換える。
replica[2] = 500;
//original配列の中身を出力。
System.out.println("original配列の中身を出力");
Arrays.stream(original).forEach(i -> System.out.print(i +" "));
System.out.println(System.getProperty("line.separator"));
//replica配列の中身を出力。
System.out.println("replica配列の中身を出力");
Arrays.stream(replica).forEach(i -> System.out.print(i +" "));
System.out.println(System.getProperty("line.separator"));
実行結果
original配列の中身を出力
10 20 30 40 50
replica配列の中身を出力
10 20 500 40 50
オブジェクトからなる配列をコピーする際は、コピー元の配列の変数を基にインタンスを生成して代入すると、ディープコピーになります。
Java
//コピー元の配列を生成
Axis[] original = {new Axis(10,20), new Axis(30,40)};
//違う配列へコピー。
Axis[] replica = new Axis[original.length];
//originalの値をreplicaへコピーする。
for(int i = 0; i < original.length; i++) {
replica[i] = new Axis(original[i].x, original[i].y);
}
//書き換え前の値を出力。
System.out.println("前:" + original[0].x);
System.out.println("前:" + replica[0].x);
//値を書き換える。
replica[0].x=555;
//書き換え後の値を出力。
System.out.println("後:" + original[0].x);
System.out.println("後:" + replica[0].x);
実行結果
前:10
前:10
後:10
後:555
まず、コピーしたいオブジェクトを、以下のようにCloneable
インターフェースをimplements
し、clone
メソッドをオーバーライドします。
Axis.java
public class Axis implements Cloneable{
int x;
int y;
//コンストラクタ
public Axis(int x, int y) {
super();
this.x = x;
this.y = y;
}
//ゲッターセッター
public int getX() {return x;}
public void setX(int x) {this.x = x;}
public int getY() {return y;}
public void setY(int y) {this.y = y;}
//cloneメソッドを実装
public Axis clone(){
Axis result = new Axis(this.x, this.y);
result.x = this.x;
result.y = this.y;
return result;
}
}
以下のようにclone
メソッドを呼び出します。
Java
//コピー元の配列を生成
Axis[] original = {new Axis(10,20), new Axis(30,40)};
//違う配列へコピー。
Axis[] replica = {original[0].clone(), original[1].clone()};
//書き換え前の値を出力。
System.out.println("前:" + original[0].x);
System.out.println("前:" + replica[0].x);
//値を書き換える。
replica[0].x=555;
//書き換え後の値を出力。
System.out.println("後:" + original[0].x);
System.out.println("後:" + replica[0].x);
実行結果
前:10
前:10
後:10
後:555
もし、オブジェクト型のフィールドがいる場合は、そのオブジェクト型にもclone
メソッドをオーバーライドしたうえで、result.obj = this.obj.clone();
と記述する必要があります。(25行目)
Java
public class Axis implements Cloneable{
int x;
int y;
ObjectABC obj;
//コンストラクタ
public Axis(int x, int y, this.obj) {
super();
this.x = x;
this.y = y;
this.obj = obj;
}
//ゲッターセッター
public int getX() {return x;}
public void setX(int x) {this.x = x;}
public int getY() {return y;}
public void setY(int y) {this.y = y;}
//cloneメソッドを実装
public Axis clone(){
Axis result = new Axis(this.x, this.y, this.obj);
result.x = this.x;
result.y = this.y;
result.obj = this.obj.clone();
return result;
}
}
以上で記事の解説はお終い!
もっとJavaやSpringを勉強したい方にはUdemyがオススメ!同僚に差をつけよう!