ホームページ  >  記事  >  Java  >  Java におけるオブジェクトの深いコピー (ディープ クローン) と浅いコピー (シャロー クローン) のシリアル化

Java におけるオブジェクトの深いコピー (ディープ クローン) と浅いコピー (シャロー クローン) のシリアル化

高洛峰
高洛峰オリジナル
2016-11-23 10:06:221909ブラウズ

1.浅いコピーと深いコピーの概念

⑴浅いコピー(浅いクローン)

コピーされたオブジェクトのすべての変数には元のオブジェクトと同じ値が含まれており、他のオブジェクトへの参照はすべて元のオブジェクトを指し続けます。つまり、浅いコピーは、参照しているオブジェクトではなく、問題のオブジェクトのみをコピーします。

例:

List を複製する一般的な方法はたくさんあります。List の浅いコピーの一般的な方法をいくつか挙げてみましょう:

public static void main(String []args){

  List<Map<String,String>> list1 = new ArrayList<Map<String, String>>();

   Map<String,String> map = new HashMap<String, String>();

   map.put("name", "xiaoming");

   map.put("age", "28");

   list1.add(map);

   //克隆方法1:利用原list1作为参数直接构造方法生成。

   List<Map<String,String>> list2 = new ArrayList<Map<String, String>>(list1);

    //克隆方法2:手动遍历将原list1中的元素全部添加到复制表中。

   for(int i = 0, l = list1.size(); i < l; i++)

       list2.add(list1.get(i));

//克隆方法3:调用Collections的静态工具方法 Collections.copy


//克隆方法4:使用System.arraycopy方法进行复制


}

List 自体はオブジェクトです。クラス型を格納する場合、アドレスの格納のみを行います。基本型を保存する場合、保存されるのは実際の値です。リストが何千もあるとしても、要素はほんのわずかです。再構築、Collections の copy メソッド、System の copy メソッド、または手動トラバースのいずれであっても、結果は同じです。これらのメソッドは、古い要素を指すいくつかのアドレスを追加するだけで、ArrayList オブジェクト自体を変更するだけです。ディープコピーは行われませんでした。 (また、新しい新しいオブジェクトの操作はまったくありません。) 場合によっては、元のメモリ内の要素を単に使用するのではなく、これらの要素をコピーする必要がある場合があります。リスト層はこの問題を実装します。 Java 言語は、ヒープ メモリに埋め込まれたこれらのデータの操作を避けるために、最初から考慮されていました。すべての操作は、それらが見つかるアドレスに向けられます。アドレス自体が失われると、GC によって消去されます。したがって、少しずつトラバースし、new で新しいオブジェクトを作成し、元の値を割り当てる必要があります。上記のアプローチを少しアレンジして、シリアル化されたオブジェクトを使ってIOストリーム内でデータを走り回らせてコピーできるようにしたと感じるかもしれないと言われています。実際、Java 言語は、オブジェクトをストリームにシリアル化する際に、実際に危険にさらされています。結局のところ、単にアドレスを投げ込むことはできません。さらに、IO フローは他のシステムと対話する必要があります。誰かにアドレスを送信して、どのヒープでそれを見つけるように依頼しますか?したがって、ヒープメモリを新たに確保する必要があることは言うまでもありません。

⑵ディープコピー(ディープクローン)のシリアル化

コピーされたオブジェクトのすべての変数には、他のオブジェクトを参照する変数を除き、元のオブジェクトと同じ値が含まれます。他のオブジェクトを参照する変数は、元の参照オブジェクトではなく、コピーされた新しいオブジェクトを指します。つまり、ディープ コピーでは、コピー対象のオブジェクトが参照するすべてのオブジェクトがコピーされます。

Java でディープ コピー (ディープ クローン作成) を行うにはシリアル化を使用します (より複雑なオブジェクトのディープ コピーの clone() メソッドの書き換えを避けるために、ブレークポイント再開やその他の関数を実装するようにプログラムすることもできます)

オブジェクトストリームに書き込むプロセスはシリアル化プロセスですが、Java では、これは非常に明確に「フリーズ」または「ピックリング」プロセスとも呼ばれ、ストリームからのオブジェクトの読み取りの並列化 (逆シリアル化) プロセスは「解凍」または「」とも呼ばれます。デピッキング」の工程。 ストリームに書き込まれるのはオブジェクトのコピーであり、元のオブジェクトは JVM 内にまだ存在するため、「ピクルスに漬けられる」ものはオブジェクトのコピーにすぎず、Java ピクルスはオブジェクトのコピーであることに注意してください。まだ新鮮です。 Java 言語でオブジェクトをディープ コピーするには、多くの場合、最初にオブジェクトに Serializable インターフェイスを実装させ、次にオブジェクト (実際にはオブジェクトの単なるコピー) をストリームに書き込み (ピクルにピックルし)、それからそれを読み取ることができます。ストリームから取り出すと (ピクルスを新鮮な状態でストリームに戻します)、オブジェクトを再構築できます。 以下はソース コードのディープ コピーです。

public List<Map<String,String>> deClone(Object obj) throws IOException,OptionalDataException,ClassNotFoundException{
//将对象写到流里
ByteArrayOutoutStream bo=new ByteArrayOutputStream();
ObjectOutputStream oo=new ObjectOutputStream(bo);
oo.writeObject(obj);//从流里读出来
ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi=new ObjectInputStream(bi);
return(oi.readObject());
}

その前提は、オブジェクトとそのオブジェクト内で参照されるすべてのオブジェクトがシリアル化可能であることです。そうでない場合は、それらのシリアル化不可能なオブジェクトまたは属性を一時的に設定して、コピー プロセスの外で除外できるかどうかを慎重に検討する必要があります。 。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。