第29回 シャローコピーとディープコピー
今回のテーマは「シャローコピーとディープコピー」です。
まずは「シャローコピーとは何ぞや」というところから始めましょう。 シャロー(shallow )とは「浅い」という意味です。 では、シャローコピーはいったい何を「浅い」としているのでしょうか。 この疑問を解決するために、前回説明したcloneメソッドを利用して説明していきます。 というのは、JavaのObjectクラスのcloneメソッドの実装はシャローコピーだからです。 前回cloneメソッドを使用した際にシャローコピーが行われていたのですね。
それでは前回と似たようなソースで確認していきましょう。 まずはいつものSportsインターフェースとその具象クラスです。
public interface Sports {
void play();
}
public class Badminton implements Sports {
@Override
public void play() {
System.out.println("バドミントンして遊びます。");
}
}
Playerクラスには、シャローコピーを説明しやすくするために、getterを一つ追加しました。
前回と同じくCloneableインターフェースをインプリメントしています。
public class Player implements Cloneable {
private Sports sports;
public Player(Sports sports) {
this.sports = sports;
System.out.println("コンストラクタです。");
}
public Sports getSports() {
return sports;
}
public void play() {
System.out.println("ウォームアップします。");
sports.play();
System.out.println("クールダウンします。");
}
}
Mainクラスでは実際に複製を行い、シャローコピーを理解するためのインスタンスの比較を行っています。 なお、今回は汎用的なclone生成メソッドを用意しました。 最後のキャスト時に型の安全性に関して、コンパイラから警告が出されてしまうので、SuppressWarningsアノテーションにより警告されないようにしています。 cloneメソッドがオーバーライドされていない限り、シャローコピーされます。
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws Exception {
Player player = new Player(new Badminton());
player.play();
System.out.println();
Player clonePlayer = createClone(player);
clonePlayer.play();
System.out.println();
System.out.print("Playerのインスタンスが同じ:");
System.out.println(player == clonePlayer);
System.out.print("Sportsのインスタンスが同じ:");
System.out.println(player.getSports() == clonePlayer.getSports());
}
@SuppressWarnings("unchecked")
public static <T extends Cloneable> T createClone(T t) throws Exception {
if (t == null) {
return null;
}
Method cloneMethod = Object.class.getDeclaredMethod("clone");
cloneMethod.setAccessible(true);
return (T) cloneMethod.invoke(t);
}
}
このプログラムを実行したら、複製を行ったPlayerのインスタンスは異なりますが、PlayerクラスのフィールドのSportsのインスタンスが同じという結果が出ます。 どうしてこうなるのでしょうか。
実はシャローコピーの場合、int等のプリミティブ型はそのままコピーされますが、参照型に関しては、あくまで参照がコピーされるだけであって、参照先のインスタンスがコピーされるわけではないのです。 じゃあ、参照先のインスタンスごとコピーする場合は何かというと、それがディープコピーなのです。 参照をコピーするのか、参照先のインスタンスごとコピーするのかについて、浅い深いと言っているわけですね。
シャローコピーとディープコピーの違いをしっかり理解して、状況に応じて適切に使い分けられるようになりましょう。

