この記事は、Java オブジェクトのディープ クローン作成を実現するためのシリアル化されたアクセスの方法の詳細な分析と紹介です。必要な方は参照してください。
Java では、非プロトタイプ型のオブジェクト参照が割り当てられることはわかっています。別のオブジェクトの参照の後、2 つの参照は次のように同じオブジェクトを指します:
コードは次のとおりです:
public class DeepCloneTest { private class CloneTest { private Long myLong = new Long(1); } public static void main(String args[]) { new DeepCloneTest().Test(); } public void Test() { CloneTest ct1 = new CloneTest(); CloneTest ct2 = ct1; // to see if ct1 and ct2 are one same reference. System.out.println("ct1: " + ct1); System.out.println("ct2: " + ct2); // if ct1 and ct2 point to one same object, then ct1.myLong == ct2.myLong. System.out.println("ct1.myLong: " + ct1.myLong); System.out.println("ct2.myLong: " + ct2.myLong); // we change ct2's myLong ct2.myLong = 2L; // to see whether ct1's myLong was changed. System.out.println("ct1.myLong: " + ct1.myLong); System.out.println("ct2.myLong: " + ct2.myLong); }}
out put:
ct1: DeepCloneTest$CloneTest@c17164
ct2: DeepCloneTest$CloneTest@ c17164
ct1 .myLong: 1
ct2.myLong: 1
ct1.myLong: 2
ct2.myLong: 2
これはJavaを勉強している人なら誰でも知っていると思います(知らない人は?)。 。
メモリ内では、オブジェクトの参照はスタックに格納され、オブジェクトのデータはヒープに格納され、スタック内の参照はヒープ内のオブジェクトを指します。以下は 2 つのスタック内の参照で、ヒープ内の同じオブジェクトを指しています。したがって、ct2 の myLong が変更されると、ct1 の myLong の値も変更されることが簡単にわかります。理解してください:
この領域には同じ値を持つ 2 つの参照があります。それらは右側のヒープ領域にある同じオブジェクトを指します。ほとんどの場合、Java 言語のこの機能を使用して、やりたいことを実行します。たとえば、オブジェクト参照を入力パラメータとしてメソッドに渡し、メソッド内で、指定されたオブジェクトに対応する変更を加えます。参照により。しかし、場合によっては、既存のオブジェクトと全く同じ内容を持つが、別のオブジェクトを参照するオブジェクトを構築したい場合があります。これを行うには、
これを行うことができます:
public class DeepCloneTest{ // must implements Cloneable. private class CloneTest implements Cloneable{ private Object o = new Object(); public CloneTest clone() { CloneTest ct = null; try { ct = (CloneTest)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return ct; } } public static void main(String args[]) { new DeepCloneTest().Test(); } public void Test() { CloneTest ct1 = new CloneTest(); CloneTest ct2 = ct1.clone(); // to see if ct1 and ct2 are one same reference. System.out.println("ct1: " + ct1); System.out.println("ct2: " + ct2); // whether ct1.o == ct2.o ? yes System.out.println("ct1.o " + ct1.o); System.out.println("ct1.o " + ct1.o); }}
ct1: DeepCloneTest $CloneTest@c17164
ct2: DeepCloneTest$CloneTest@1fb8ee3
ct1.o java.lang.Object@61de33
ct1.o java.lang.Object@61de33
出力からわかります: ct1 と ct2確かに 2 つの異なる Reference であるため、ct1.o と ct2.o も 2 つの異なるオブジェクトであることは当然のことと考えられますが、出力からはそうではないことがわかります。 ct1.o と ct2.o は同じオブジェクトです。その理由は、クローン作成が使用されているとはいえ、上記はグラフィカルに表現された浅いクローンにすぎないからです:
上の o を見ましたか?実際、これは 2 つのオブジェクトによって共有されます。これは、もともと羊が入っている羊小屋 1 があり、その後羊小屋 2 を作成したことと同じです。羊小屋 1 から羊を取り出さずに、羊小屋 2 にも羊を入れたと思っています。二匹の羊、でも実際は?誰もが知っている。
これは浅い複製の結果です: 2 つのオブジェクトに独立した o を持たせたい場合は、o を再度複製する必要があります。 「そんなことは何もない、やればいい」と思う人もいるかもしれませんが、oが複数あり、oに似たものがたくさんある場合、それらを1つずつクローンすることを考えたことはありますか?明らかに非現実的です。
1 つの解決策は次のとおりです。 まずオブジェクトをシリアル化してストリームに保存し、次にストリームからオブジェクトを読み取ります。これにより、完全なコピーのように、読み取られたデータが前のオブジェクトとまったく同じ値になります。 。
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class DeepCloneTest { // must implements Cloneable. private class CloneTest implements Serializable{ private static final long serialVersionUID = 1L; private Object o = new Object(); public CloneTest deepClone() { CloneTest ct = null; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois= new ObjectInputStream(bais); ct = (CloneTest)ois.readObject(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return ct; } } public static void main(String args[]) { new DeepCloneTest().Test(); } public void Test() { CloneTest ct1 = new CloneTest(); CloneTest ct2 = ct1.deepClone(); // to see if ct1 and ct2 are one same reference. System.out.println("ct1: " + ct1); System.out.println("ct2: " + ct2); // whether ct1.o == ct2.o ? no System.out.println("ct1.o " + ct1.o); System.out.println("ct1.o " + ct1.o); } }
この時点でメモリ内のデータは次のようになります:
以上がJavaシリアル化アクセスによるオブジェクト複製例の詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。