オブジェクトの複製には、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]