以下のコードを見てください。
DummyBean dum = new DummyBean();
dum.setDummy("foo");
System.out.println(dum.getDummy()); // prints 'foo'
DummyBean dumtwo = dum;
System.out.println(dumtwo.getDummy()); // prints 'foo'
dum.setDummy("bar");
System.out.println(dumtwo.getDummy()); // prints 'bar' but it should print 'foo'
そのため、dum
をdumtwo
にコピーし、dum
に影響を与えずにdumtwo
を変更したいと思います。しかし、上記のコードはそれをしていません。 dum
で何かを変更すると、dumtwo
でも同じ変更が行われます。
dumtwo = dum
と言うと、Javaは 参照のみ をコピーします。それで、dum
の新しいコピーを作成し、それをdumtwo
に割り当てる方法はありますか?
コピーコンストラクタを作成します。
class DummyBean {
private String dummy;
public DummyBean(DummyBean another) {
this.dummy = another.dummy; // you can access
}
}
すべてのオブジェクトには、オブジェクトのコピーに使用できるcloneメソッドもありますが、使用しないでください。クラスを作成して不適切なクローンメソッドを作成するのはとても簡単です。それをするつもりなら、少なくともJoshua Blochがそれについて言っていることをEffective Javaに読んでください。
基本: Javaでのオブジェクトのコピー。
2つのオブジェクト、 includedObj1 および includedObj2 を含むobject- obj1
を想定します。
浅いコピー:
シャローコピーは、同じクラスの新しいinstance
を作成し、すべてのフィールドを新しいインスタンスにコピーして返します。 オブジェクトクラス はclone
メソッドを提供し、シャローコピーをサポートします。
ディープコピー:
ディープコピーは、オブジェクトが、それが参照しているオブジェクトと一緒にコピーされるの場合に発生します。以下の画像は、ディープコピーが実行された後のobj1
を示しています。 obj1
がコピーされただけではないしかし、その中に含まれるオブジェクトも同様にコピーされています。 Java Object Serialization
を使ってディープコピーを作成することができます。残念ながら、この方法にもいくつか問題があります( 詳細な例 )。
考えられる問題: clone
は正しく実装するのが難しいです。
防衛的なコピー 、 コピーコンストラクタ (@egagaの回答として)、または 静的ファクトリメソッド を使用することをお勧めします。
clone()
メソッドを持っていることを知っているけれども、あなたがコンパイル時にオブジェクトのタイプを知らないならば、あなたは問題を抱えています。 JavaにはCloneable
というインターフェースがあります。実際には、オブジェクトをCloneable
にしたい場合は、このインタフェースを実装する必要があります。 Object.clone
は protected なので、アクセスできるようにするにはパブリックメソッドでオーバーライドする必要があります。clone()
メソッドもディープコピーを実行すると仮定します。これは仮定のリスクが高すぎるためです。あなたはすべてのクラスでコードを制御しなければなりません。たとえば org.Apache.commons.lang.SerializationUtils には、シリアライゼーションを使用したディープクローン用のメソッドがあります( Source )。 Beanのクローンを作成する必要がある場合は、 org.Apache.commons.beanutils ( Source )に2つのユーティリティメソッドがあります。
cloneBean
は、利用可能なプロパティの取得メソッドおよび設定メソッドに基づいてBeanを複製します。copyProperties
は、プロパティ名が同じである場合はすべて、OriginのBeanから宛先のBeanにプロパティ値をコピーします。パッケージimport org.Apache.commons.lang.SerializationUtils;
にはメソッドがあります。
SerializationUtils.clone(Object);
例:
this.myObjectCloned = SerializationUtils.clone(this.object);
以下のようにしてください。
public class Deletable implements Cloneable{
private String str;
public Deletable(){
}
public void setStr(String str){
this.str = str;
}
public void display(){
System.out.println("The String is "+str);
}
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
別のオブジェクトを入手したい場合は、単純にクローン作成を実行してください。例:
Deletable del = new Deletable();
Deletable delTemp = (Deletable ) del.clone(); // this line will return you an independent
// object, the changes made to this object will
// not be reflected to other object
Reflection APIを使用しても回答がないのはなぜですか?
private static Object cloneObject(Object obj){
try{
Object clone = obj.getClass().newInstance();
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
field.set(clone, field.get(obj));
}
return clone;
}catch(Exception e){
return null;
}
}
とても簡単です。
編集:再帰を介して子オブジェクトを含める
private static Object cloneObject(Object obj){
try{
Object clone = obj.getClass().newInstance();
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
if(field.get(obj) == null || Modifier.isFinal(field.getModifiers())){
continue;
}
if(field.getType().isPrimitive() || field.getType().equals(String.class)
|| field.getType().getSuperclass().equals(Number.class)
|| field.getType().equals(Boolean.class)){
field.set(clone, field.get(obj));
}else{
Object childObj = field.get(obj);
if(childObj == obj){
field.set(clone, clone);
}else{
field.set(clone, cloneObject(field.get(obj)));
}
}
}
return clone;
}catch(Exception e){
return null;
}
}
GoogleのJSONライブラリを使用してシリアル化し、シリアル化されたオブジェクトの新しいインスタンスを作成します。いくつかの制限付きでディープコピーを行います。
再帰的参照はあり得ません
異種の型の配列はコピーされません
配列とリストは型付けされるべきであり、そうでなければインスタンス化するクラスを見つけることができません
自分で宣言したクラスに文字列をカプセル化する必要があるかもしれません。
また、このクラスを使用して、ユーザー設定、ウィンドウ、および実行時に再ロードする必要がないものを保存します。使い方はとても簡単で効果的です。
import com.google.gson.*;
public class SerialUtils {
//___________________________________________________________________________________
public static String serializeObject(Object o) {
Gson gson = new Gson();
String serializedObject = gson.toJson(o);
return serializedObject;
}
//___________________________________________________________________________________
public static Object unserializeObject(String s, Object o){
Gson gson = new Gson();
Object object = gson.fromJson(s, o.getClass());
return object;
}
//___________________________________________________________________________________
public static Object cloneObject(Object o){
String s = serializeObject(o);
Object object = unserializeObject(s,o);
return object;
}
}
はい、あなたはただオブジェクトを参照しています。 Cloneable
が実装されていれば、オブジェクトを複製することができます。
オブジェクトのコピーに関するこのウィキの記事をチェックしてください。
はい。 ディープコピー あなたのオブジェクトが必要です。
クラスにCloneable
以下のコードを追加します。
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
これを使用してくださいclonedObject = (YourClass) yourClassObject.clone();
これが必要になった場合のclone()
のわかりやすい説明です。
これもうまくいきます。想定モデル
class UserAccount{
public int id;
public String name;
}
最初に compile 'com.google.code.gson:gson:2.8.1'
をあなたのアプリに追加してください。それから
Gson gson = new Gson();
updateUser = gson.fromJson(gson.toJson(mUser),UserAccount.class);
アクセス修飾子の後にtransient
キーワードを使用すると、フィールドの使用を除外できます。
注: これは悪い習慣です。また、Cloneable
やJavaSerialization
の使用はお勧めしません。遅くて壊れています。最高のパフォーマンスのためのコピーコンストラクタを書く ref 。
何かのようなもの
class UserAccount{
public int id;
public String name;
//empty constructor
public UserAccount(){}
//parameterize constructor
public UserAccount(int id, String name) {
this.id = id;
this.name = name;
}
//copy constructor
public UserAccount(UserAccount in){
this(in.id,in.name);
}
}
90000反復のテスト統計:
行UserAccount clone = gson.fromJson(gson.toJson(aO), UserAccount.class);
は 808ms を取ります
行UserAccount clone = new UserAccount(aO);
は 1ms 以下になります
結論: 上司が頭がおかしくてスピードが好きならgsonを使ってください。あなたが品質を好むならば、セカンドコピーコンストラクタを使用してください。
Android Studioではコピーコンストラクタコード ジェネレータプラグイン を使用することもできます。
あなたの答えはディープクローニングで、これにはCloneable
インターフェースを実装し、clone()
メソッドをオーバーライドする必要があります。
public class DummyBean implements Cloneable {
private String dummy;
public void setDummy(String dummy) {
this.dummy = dummy;
}
public String getDummy() {
return dummy;
}
@Override
public Object clone() throws CloneNotSupportedException {
DummyBean cloned = (DummyBean)super.clone();
cloned.setDummy(cloned.getDummy());
// the above is applicable in case of primitive member types,
// however, in case of non primitive types
// cloned.setNonPrimitiveType(cloned.getNonPrimitiveType().clone());
return cloned;
}
}
これを DummyBean dumtwo = dum.clone();
と呼びます。
そのためには、何らかの方法でオブジェクトを複製する必要があります。 Javaにはクローン作成メカニズムがありますが、必要でなければ使用しないでください。コピーがうまくいくようなコピー方法を作成してから、次のようにします。
dumtwo = dum.copy();
ここで は、コピーを完成させるためのさまざまなテクニックに関するより多くのアドバイスです。
ディープクローニングユーティリティを使用します。
SomeObjectType copy = new Cloner().deepClone(someObject);
これはどんなJavaオブジェクトでも深くコピーするでしょう、 https://github.com/kostaskougios/cloning でそれをチェックしてください。
明示的にコピーする以外に、他のアプローチはオブジェクトを不変にすることです(set
や他のミューテーターメソッドはありません)。このようにして問題は起こりません。不変性は大きなオブジェクトではより難しくなりますが、それとは反対に、一貫性のある小さなオブジェクトとコンポジットに分割する方向に進むということです。
class DB {
private String dummy;
public DB(DB one) {
this.dummy = one.dummy;
}
}
コピーしたいオブジェクトを渡して、必要なオブジェクトを取得します。
private Object copyObject(Object objSource) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(objSource);
oos.flush();
oos.close();
bos.close();
byte[] byteData = bos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
try {
objDest = new ObjectInputStream(bais).readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
return objDest;
}
objDest
を目的のオブジェクトに解析します。
ハッピーコーディング!
http://x-stream.github.io/ - から、XStreamを使って自動的にディープコピーすることができます。
XStreamはオブジェクトをXMLにシリアライズし、またに戻すためのシンプルなライブラリです。
それをあなたのプロジェクトに追加してください(mavenを使用している場合)
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.3.1</version>
</dependency>
それから
DummyBean dum = new DummyBean();
dum.setDummy("foo");
DummyBean dumCopy = (DummyBean) XSTREAM.fromXML(XSTREAM.toXML(dum));
これであなたはどんなクローニングインタフェースも実装する必要なしでコピーを持っています。
Cloneable
を実装してclone()
メソッドを使うことができます。ただし、cloneメソッドを使用する場合は、必ず標準でObject
のpublic Object clone()
メソッドをオーバーライドしてください。
注釈をソースファイルに追加できる場合は、 this this のような注釈プロセッサまたはコードジェネレータを使用できます。
import net.zerobuilder.BeanBuilder
@BeanBuilder
public class DummyBean {
// bean stuff
}
手動で行うのと同じ方法で、シャローコピーを作成するための静的メソッドDummyBeanBuilders
を持つクラスdummyBeanUpdater
が生成されます。
DummyBean bean = new DummyBean();
// Call some setters ...
// Now make a copy
DummyBean copy = DummyBeanBuilders.dummyBeanUpdater(bean).done();
public class MyClass implements Cloneable {
private boolean myField= false;
// and other fields or objects
public MyClass (){}
@Override
public MyClass clone() throws CloneNotSupportedException {
try
{
MyClass clonedMyClass = (MyClass)super.clone();
// if you have custom object, then you need create a new one in here
return clonedMyClass ;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return new MyClass();
}
}
}
そしてあなたのコードで:
MyClass myClass = new MyClass();
// do some work with this object
MyClass clonedMyClass = myClass.clone();