Javaでは、ディープオブジェクトコピー機能を実装するのが少し難しいです。元のオブジェクトと複製されたオブジェクトが確実に参照を共有しないようにするために必要な手順は?Javaでオブジェクトのディープコピーを作成するにはどうすればよいですか?
答えて
安全な方法は、オブジェクトをシリアル化して逆シリアル化することです。これは、すべてがまったく新しいリファレンスであることを保証します。
Here's an articleこれを効率的に行う方法については、
警告:新しいインスタンスがではなくでないように、クラスがシリアル化をオーバーライドすることは可能です。シングルトンの場合あなたのクラスがシリアライズ可能でない場合、これはもちろん動作しません。
記事で提供されているFastByteArrayOutputStream実装がより効率的になる可能性があることに注意してください。バッファがいっぱいになるとArrayListスタイルの展開が使用されますが、LinkedListスタイルの展開方法を使用する方が効果的です。新しい2xバッファを作成し、現在のバッファをmemcpyする代わりに、バッファのリンクリストを維持し、現在のバッファがいっぱいになると新しいバッファを追加します。デフォルトのバッファサイズよりも多くのデータを書き込む要求がある場合は、要求とまったく同じ大きさのバッファノードを作成してください。ノードは同じサイズである必要はありません。 –
ちょうどkryoを使用してください:https://github.com/EsotericSoftware/kryo#copyingcloningベンチマークhttp://www.slideshare.net/AlexTumanoff/serialization-and-performance – zengr
シリアル化による深いコピーを説明している良い記事:http ://www.javaworld.com/article/2077578/learn-java/java-tip-76--an-alternative-to-the-deep-copy-technique.html –
ディープコピーは、各クラスの同意がある場合にのみ行うことができます。クラス階層を制御できる場合は、クローン可能なインタフェースを実装して、Cloneメソッドを実装できます。それ以外の場合、オブジェクトが非データリソース(データベース接続など)を共有している可能性があるため、完全コピーを実行することは安全には不可能です。一般的に、ディープ・コピーはJava環境では悪い習慣とみなされ、適切な設計方法で避けるべきです。
「適切な設計方法」について教えてください。 – eftokay83
Commons Langでorg.apache.commons.lang3.SerializationUtils.clone(T)
を使用してシリアル化ベースのディープクローンを実行できますが、パフォーマンスは非常に悪いです。
一般に、クローン作成が必要なオブジェクトグラフには、オブジェクトの各クラスごとに独自のクローンメソッドを記述することをお勧めします。
XStream(http://x-stream.github.io/)を使用してください。アノテーションで無視できるプロパティや、XStreamクラスのプロパティ名を明示的に指定することもできます。さらに、クローン可能なインタフェースを実装する必要はありません。
このような場合、XStreamは本当に便利です。ここではいくつかの人々が使用してまたは上書きObject.clone()
言及している
private static final XStream XSTREAM = new XStream();
...
Object newObject = XSTREAM.fromXML(XSTREAM.toXML(obj));
クローニング行う簡単なコードです。それをしないでください。 Object.clone()
にはいくつかの重大な問題があり、ほとんどの場合、その使用は推奨されません。ジョシュア・ブロッホの「Effective Java」の項目11を参照してください。私は安全にObject.clone()
をプリミティブ型の配列に使うことができると信じていますが、それ以外には、適切にクローンを使用してオーバーライドすることを賢明にする必要があります。
シリアライゼーション(XMLなど)に依存しているスキームは、クルージングです。
ここで簡単な答えはありません。オブジェクトをディープコピーする場合は、オブジェクトグラフをトラバースし、各子オブジェクトをオブジェクトのコピーコンストラクタまたは静的ファクトリメソッドを介して明示的にコピーする必要があります。 Immutables(例:String
)はコピーする必要はありません。脇に、あなたはこの理由のために不変性を好むべきです。
import com.thoughtworks.xstream.XStream;
public class deepCopy {
private static XStream xstream = new XStream();
//serialize with Xstream them deserialize ...
public static Object deepCopy(Object obj){
return xstream.fromXML(xstream.toXML(obj));
}
}
ファイルを作成せずにシリアライズでディープコピーを作成できます。
ディープコピーするオブジェクトにはimplement serializable
が必要です。クラスがfinalでないか、または変更できない場合は、クラスを拡張してシリアライズ可能に実装します。
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(object);
oos.flush();
oos.close();
bos.close();
byte[] byteData = bos.toByteArray();
はバイトストリームからクラスを復元します:バイトのストリームにあなたのクラスに変換
深いコピーを実装するために
ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
(Object) object = (Object) new ObjectInputStream(bais).readObject();
クラスが最終的な場合はどのように拡張しますか? –
@KumarManishクラスMyContainerは、Serializable {MyFinalClassインスタンスを実装しています。 ...} –
これはすばらしい返答です。クローンが混乱している – blackbird014
一つの方法は、それぞれ関連するにコピーコンストラクタを追加することですクラス。コピーコンストラクタは 'this'のインスタンスを単一の引数として引数からすべての値をコピーします。かなりの仕事ですが、かなり簡単で安全です。
編集:フィールドを読み取るためにアクセサメソッドを使用する必要はありません。ソースインスタンスは常にコピーコンストラクタのインスタンスと同じ型なので、すべてのフィールドに直接アクセスできます。明らかだが、見落とされるかもしれない。
例:
public class Order {
private long number;
public Order() {
}
/**
* Copy constructor
*/
public Order(Order source) {
number = source.number;
}
}
public class Customer {
private String name;
private List<Order> orders = new ArrayList<Order>();
public Customer() {
}
/**
* Copy constructor
*/
public Customer(Customer source) {
name = source.name;
for (Order sourceOrder : source.orders) {
orders.add(new Order(sourceOrder));
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
編集:コピーコンストラクタを使用しているとき、あなたがコピーしているオブジェクトの実行時の型を知っておく必要があることに注意してください。上記の方法では、混合リストを簡単にコピーすることはできません(リフレクションコードで行うこともできます)。
コピーしているものがサブクラスであるが、親によって参照されているというケースに興味があります。コピーコンストラクタをオーバーライドすることは可能ですか? –
親クラスがそのサブクラスを参照するのはなぜですか?あなたは例を挙げることができますか? –
public class Car extends Vehicle そして車を乗り物として参照してください。 originaList = new ArrayList
非常に簡単で簡単なアプローチの1つは、Jackson JSONを使用して複雑なJavaオブジェクトをJSONにシリアル化して読み戻すことです。
リンクが無効です。 –
あなたは、単純なAPIを持ち、かつ反射と比較的高速クローニングを行いuse a libraryは、(直列化メソッドよりも高速でなければなりません)することができます。
Cloner cloner = new Cloner();
MyClass clone = cloner.deepClone(o);
// clone is a deep-clone of o
Apacheコモンズは、オブジェクトを深くクローンするための速い方法を提供します。
My_Object object2= org.apache.commons.lang.SerializationUtils.clone(object1);
テスト済みで安定したライブラリを提案するためのupvote – katzenhut
1)
ここpublic static Object deepClone(Object object) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
}
catch (Exception e) {
e.printStackTrace();
return null;
}
}
2)
// (1) create a MyPerson object named Al
MyAddress address = new MyAddress("Vishrantwadi ", "Pune", "India");
MyPerson al = new MyPerson("Al", "Arun", address);
// (2) make a deep clone of Al
MyPerson neighbor = (MyPerson)deepClone(al);
あなたMyPersonとこのMyAddressクラスは複雑なオブジェクトの場合serilazableインタフェース
を実装する必要がありますし、パフォーマンスが重要ではないときに私はシリアル化するためにgson のように、JSONライブラリを使用オブジェクトをjsonのテキストに変換し、次に新しいオブジェクトを取得するためにテキストを逆シリアル化します。
transient
フィールドはコピーされず、循環参照を持つオブジェクトはStackOverflowError
であることを除いて、ほとんどの場合、反射に基づくgsonが機能します。 春のフレームワークユーザーの場合
public static <T> T Copy(T AnObject, Class<T> ClassInfo)
{
Gson gson = new GsonBuilder().create();
String text = gson.toJson(AnObject);
T newObject = gson.fromJson(text, ClassInfo);
return newObject;
}
public static void main(String[] args)
{
String originalObject = "hello";
String copiedObject = Copy(originalObject, String.class);
}
あなた自身と私たちのためにJavaの命名規則に従ってください。 –
。クラスorg.springframework.util.SerializationUtils
使用:
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T object) {
return (T) SerializationUtils.deserialize(SerializationUtils.serialize(object));
}
- 1. オブジェクトのJavaディープコピーを作成するにはどうすればよいですか?
- 2. このコピーコンストラクタをJavaでディープコピーを作成するにはどうすればよいですか?
- 3. Javaで2次元配列のディープコピーを作成するにはどうすればよいですか?
- 4. observablesとcomputedを含むmobxクラスのディープコピーを作成するにはどうすればよいですか?
- 5. RubyでProcをディープコピーするにはどうすればよいですか?
- 6. Javaでオンスクリーンキーボードを作成するにはどうすればよいですか?
- 7. Javaでオーディオストリーマーを作成するにはどうすればよいですか?
- 8. Javaでハッシュテーブルを作成するにはどうすればよいですか?
- 9. Javaで新しい配列オブジェクトを作成するにはどうすればよいですか?
- 10. Network.HTTP.Conduit.Requestオブジェクトを作成するにはどうすればよいですか?
- 11. オブジェクト参照を作成するにはどうすればよいですか?
- 12. Javaで複数のオブジェクトを作成するにはどうすればよいですか?
- 13. ディープコピーをJavaで作成する方法
- 14. 選択クエリの結果セットからJavaオブジェクトを作成するにはどうすればよいですか?
- 15. JavaのExampleオブジェクトからTensorを作成するにはどうすればよいですか?
- 16. 作成するオブジェクトをJavaのメソッドのパラメータとして渡すにはどうすればよいですか?
- 17. Javaでドラッグ可能オブジェクトを作成するにはどうすればよいですか?
- 18. ないJavaはオブジェクトのディープコピーを作成するか、単にその参照
- 19. Javaでカスタムソケットを作成するにはどうすればいいですか?
- 20. 2つのオブジェクトから同じ値でオブジェクトを作成するにはどうすればよいですか?
- 21. オブジェクトをJavaでコピーするにはどうすればよいですか?
- 22. PHPでは、オブジェクトを作成してオブジェクトに追加するにはどうすればよいですか?
- 23. jQueryで動的に作成された要素のディープコピーを作成するにはどうすればよいですか?
- 24. Javaユニークなオブジェクト名を作成するにはどうすればよいですか?
- 25. レルムオブジェクトをJavaオブジェクトにするにはどうすればよいですか?
- 26. ウェブサービスアプリの作成にはどうすればよいですか?
- 27. Android、XMLビューファイル、Javaのバックエンド、バックエンドJavaでカスタムビューを作成するにはどうすればよいですか?
- 28. mockedオブジェクト内でmockedオブジェクトを作成するにはどうすればよいですか?
- 29. オブジェクトはどこにJavaで作成されるのですか
- 30. javascriptで壁などのオブジェクトを作成するにはどうすればよいですか?
をKryoが組み込まれている[コピー/クローニング]のサポート(https://code.google.com/p/kryo/#Copying/cloning)。これは、オブジェクト - >バイト - >オブジェクトではなく、オブジェクトからオブジェクトへの直接コピーです。 – NateS
これは、後で尋ねられる関連する質問です。[Deep clone utility recomendation](0120-18756-1) –