「Object」クラスのメソッド「clone」の紹介と、その挙動について説明します。
オブジェクトの複製には、java.lang.Objectの「clone」メソッドを使います。cloneメソッドを自作クラスで使う場合は、cloneメソッドをオバーライドして、「Cloneable」インターフェースを実装しなければなりません。
Objectのcloneメソッドは、オブジェクトの値や参照を保存しているインスタンスを複製して、オブジェクトを複製してくれます。そのオブジェクトを自作クラスにキャストすれば、オブジェクトが複製されます。
package sample; public class MyClass implements Cloneable { public int n = 0; // cloneのオーバーライド @Override public MyClass clone() { MyClass res = null; try { // クローン res = (MyClass)super.clone(); } catch (CloneNotSupportedException e) { // 発生しないだろうと思われるエラー処理 throw new InternalError(e.toString()); } return res; } }
cloneはインスタンスを複製します。しかし、参照型のフィールドでは、オブジェクトへの参照が複製されるだけです。
┏MyClass ━┓ ┏MyClass ━┓ ┃ ┃ ┃ ┃ ┃ ┠─○n 値 →複製→ 値 n○─┨ ┃ ┃ ┠─○iArr 参照 →複製→ 参照 iArr○─┨ ┃ ┗━━━━━┛ │ │ ┗━━━━━┛ └────┬────┘ ↓ ┏━━┓同じ配列を参照 ┃配列┃ ┗━━┛
こういった複製を「シャローコピー(浅い複製)」と呼びます。
フィールドのオブジェクトも複製したい場合は、clone内でオブジェクトを複製する処理を自前で書く必要があります。
オブジェクトの内容も複製することを「ディープコピー(深い複製)」と呼びます。
package sample;
public class MyClass implements Cloneable {
public int n = 0;
public int[] iArr = {1, 2, 3};
// cloneのオーバーライド
@Override
public MyClass clone() {
MyClass res = null;
try {
// クローン
res = (MyClass)super.clone();
} catch (CloneNotSupportedException e) {
// 発生しないだろうと思われるエラー処理
throw new InternalError(e.toString());
}
// ディープコピー
res.iArr = iArr.clone();
return res;
}
}
MyClass mc1 = new MyClass();
MyClass mc2 = mc1.clone();
mc1.n = 4;
mc1.iArr[0] = 5;
System.out.println(
mc1.n + " " + Arrays.toString(mc1.iArr)
+ "\n" +
mc2.n + " " + Arrays.toString(mc2.iArr)
);
4 [5, 2, 3] 0 [1, 2, 3]