JavaのClone()メソッド

オブジェクトのクローン作成とは、オブジェクトの正確なコピーを作成することを指します。現在のオブジェクトのクラスの新しいインスタンスを作成し、そのすべてのフィールドを、このオブジェクトの対応するフィールドの内容を正確に使用して初期化します。

Java でオブジェクトのクローン作成を実行する方法

Java でオブジェクト クローンを作成するには、以下に示す 3 つの方法があります。

  1. 代入演算子を使用して参照変数のコピーを作成する
  2. clone() メソッドを使用してコピーを作成する
  3. clone() メソッドの使用法 – ディープコピー

1. 代入演算子を使用して のコピー 参照変数

Java には、オブジェクトのコピーを作成する演算子はありません。 C++ とは異なり、Java では代入演算子を使用すると、オブジェクトではなく参照変数のコピーが作成されます。これは例を挙げて説明できます。次のプログラムは同じことを示しています。

以下は、上記のトピックの実装です。

ジャワ




// Java program to demonstrate that assignment operator> // only creates a new reference to same object> import> java.io.*;> > // A test class whose objects are cloned> class> Test {> > int> x, y;> > Test()> > {> > x => 10> ;> > y => 20> ;> > }> }> > // Driver Class> class> Main {> > public> static> void> main(String[] args)> > {> > Test ob1 => new> Test();> > > System.out.println(ob1.x +> ' '> + ob1.y);> > > // Creating a new reference variable ob2> > // pointing to same address as ob1> > Test ob2 = ob1;> > > // Any change made in ob2 will> > // be reflected in ob1> > ob2.x => 100> ;> > > System.out.println(ob1.x +> ' '> + ob1.y);> > System.out.println(ob2.x +> ' '> + ob2.y);> > }> }>

出力

10 20 100 20 100 20 

2. clone() メソッドを使用してコピーを作成する

オブジェクトのコピーが作成されるクラスには、そのクラスまたはその親クラスのいずれかに public clone メソッドが必要です。

  • clone() を実装するすべてのクラスは、super.clone() を呼び出してクローンされたオブジェクト参照を取得する必要があります。
  • このクラスは、作成するオブジェクト クローンの java.lang.Cloneable インターフェースも実装する必要があります。実装しないと、そのクラスのオブジェクトでクローン メソッドが呼び出されたときに CloneNotSupportedException がスローされます。

構文:

protected Object clone() throws CloneNotSupportedException 

i) clone()メソッドの使用法 -Shallow Copy

注記 – 以下のコード例では、 clone() メソッドは、異なる hashCode 値を持つ完全に新しいオブジェクトを作成します。これは、別のメモリ位置にあることを意味します。ただし、テスト オブジェクト c が Test2 内にあるため、プリミティブ型はディープ コピーを達成していますが、このテスト オブジェクト c は依然として t1 と t2 の間で共有されています。これを克服するために、オブジェクト変数 c のディープ コピーを明示的に実行します。これについては後で説明します。

ジャワ




// A Java program to demonstrate> // shallow copy using clone()> import> java.util.ArrayList;> > // An object reference of this class is> // contained by Test2> class> Test {> > int> x, y;> }> > // Contains a reference of Test and> // implements clone with shallow copy.> class> Test2> implements> Cloneable {> > int> a;> > int> b;> > Test c => new> Test();> > public> Object clone()> throws> CloneNotSupportedException> > {> > return> super> .clone();> > }> }> > // Driver class> public> class> Main {> > public> static> void> main(String args[])> > throws> CloneNotSupportedException> > {> > Test2 t1 => new> Test2();> > t1.a => 10> ;> > t1.b => 20> ;> > t1.c.x => 30> ;> > t1.c.y => 40> ;> > > Test2 t2 = (Test2)t1.clone();> > > // Creating a copy of object t1> > // and passing it to t2> > t2.a => 100> ;> > > // Change in primitive type of t2 will> > // not be reflected in t1 field> > t2.c.x => 300> ;> > > // Change in object type field will be> > // reflected in both t2 and t1(shallow copy)> > System.out.println(t1.a +> ' '> + t1.b +> ' '> + t1.c.x> > +> ' '> + t1.c.y);> > System.out.println(t2.a +> ' '> + t2.b +> ' '> + t2.c.x> > +> ' '> + t2.c.y);> > }> }>

出力

10 20 300 40 100 20 300 40 

上記の例では、t1.clone はオブジェクト t1 の浅いコピーを返します。オブジェクトのディープ コピーを取得するには、コピーを取得した後に clone メソッドで特定の変更を行う必要があります。

ii) clone() メソッドの使用 – ディープコピー

  • オブジェクト X のディープ コピーを作成し、それを新しいオブジェクト Y に配置する場合は、参照されているオブジェクト フィールドの新しいコピーが作成され、これらの参照がオブジェクト Y に配置されます。これは、オブジェクト内の参照オブジェクト フィールドに加えられた変更を意味します。 X または Y はそのオブジェクトにのみ反映され、他のオブジェクトには反映されません。以下の例では、オブジェクトのディープ コピーを作成します。
  • ディープ コピーでは、すべてのフィールドがコピーされ、フィールドが指す動的に割り当てられたメモリのコピーが作成されます。ディープ コピーは、オブジェクトが参照先のオブジェクトとともにコピーされるときに発生します。

ジャワ




// A Java program to demonstrate> // deep copy using clone()> > // An object reference of this> // class is contained by Test2> class> Test {> > int> x, y;> }> > // Contains a reference of Test and> // implements clone with deep copy.> class> Test2> implements> Cloneable {> > int> a, b;> > > Test c => new> Test();> > > public> Object clone()> throws> CloneNotSupportedException> > {> > // Assign the shallow copy to> > // new reference variable t> > Test2 t = (Test2)> super> .clone();> > > // Creating a deep copy for c> > t.c => new> Test();> > t.c.x = c.x;> > t.c.y = c.y;> > > // Create a new object for the field c> > // and assign it to shallow copy obtained,> > // to make it a deep copy> > return> t;> > }> }> > public> class> Main {> > public> static> void> main(String args[])> > throws> CloneNotSupportedException> > {> > Test2 t1 => new> Test2();> > t1.a => 10> ;> > t1.b => 20> ;> > t1.c.x => 30> ;> > t1.c.y => 40> ;> > > Test2 t3 = (Test2)t1.clone();> > t3.a => 100> ;> > > // Change in primitive type of t2 will> > // not be reflected in t1 field> > t3.c.x => 300> ;> > > // Change in object type field of t2 will> > // not be reflected in t1(deep copy)> > System.out.println(t1.a +> ' '> + t1.b +> ' '> + t1.c.x> > +> ' '> + t1.c.y);> > System.out.println(t3.a +> ' '> + t3.b +> ' '> + t3.c.x> > +> ' '> + t3.c.y);> > }> }>

出力

10 20 30 40 100 20 300 40 

上記の例では、clone メソッドに返されるオブジェクトをコピーするために、Test クラスの新しいオブジェクトが割り当てられていることがわかります。このため、t3 はオブジェクト t1 のディープ コピーを取得します。したがって、t3 によって「c」オブジェクトフィールドに加えられた変更は、t1 には反映されません。

ディープコピーとシャローコピー

以下で説明するように、 clone() をディープ コピーとして使用する場合と、浅いコピーとして使用する場合には、特定の違いがあります。

  • 浅いコピー これはオブジェクトをコピーする方法であり、クローン作成ではデフォルトで使用されます。このメソッドでは、古いオブジェクト X のフィールドが新しいオブジェクト Y にコピーされます。オブジェクト タイプ フィールドのコピー中に、参照が Y にコピーされます。つまり、オブジェクト Y は、X が指すのと同じ場所を指します。フィールド値がはプリミティブ型であり、プリミティブ型の値をコピーします。
  • したがって、オブジェクト X または Y 内の参照オブジェクトに加えられた変更は、他のオブジェクトにも反映されます。

浅いコピーは安価で簡単に作成できます。上の例では、次の浅いコピーを作成しました。 物体。

clone メソッド() を使用する理由 クローン方式のメリット

  • 代入演算子を使用してオブジェクト参照を別の参照変数に代入すると、古いオブジェクトの同じアドレス位置を指すことになり、オブジェクトの新しいコピーは作成されません。このため、参照変数の変更は元のオブジェクトに反映されます。
  • コピー コンストラクターを使用する場合は、すべてのデータを明示的にコピーする必要があります。つまり、コンストラクター内のクラスのすべてのフィールドを明示的に再割り当てする必要があります。ただし、clone メソッドでは、新しいコピーを作成するこの作業はメソッド自体によって実行されます。したがって、余分な処理を避けるために、オブジェクトのクローン作成を使用します。