Javaでオブジェクトをコピーするにはどうすればよいですか?

815
Veera 2009-05-16 04:30.

以下のコードを検討してください。

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'

だから、に影響を与えずににコピーしdumdumtwo変更したい。しかし、上記のコードはそれを行っていません。で何かを変更すると、同じ変更が発生します。dumdumtwodumdumtwo

私が言うときdumtwo = dum、Javaは参照のみをコピーすると思います。それで、の新しいコピーを作成してdum割り当てる方法はありますdumtwoか?

23 answers

634
egaga 2009-05-16 04:35.

コピーコンストラクターを作成します。

class DummyBean {
  private String dummy;

  public DummyBean(DummyBean another) {
    this.dummy = another.dummy; // you can access  
  }
}

すべてのオブジェクトには、オブジェクトのコピーに使用できるクローンメソッドもありますが、使用しないでください。クラスを作成して不適切なクローンメソッドを実行するのは簡単すぎます。それを行う場合は、少なくともJoshuaBlochがEffectiveJavaでそれについて述べていることを読んでください。

414
Chandra Sekhar 2012-03-23 19:47.

基本: Javaでのオブジェクトのコピー。

私たちは、オブジェクト-と仮定しましょうobj1二つのオブジェクトが含まれ、containedObj1containedObj2を

浅いコピー:
浅いコピーはinstance同じクラスのnewを作成し、すべてのフィールドを新しいインスタンスにコピーして返します。オブジェクトクラスcloneメソッドを提供し、浅いコピーのサポートを提供します。

ディープコピー:ディープコピーは、オブジェクトが参照先のオブジェクトと一緒にコピーさ
れるときに発生します。下の画像はobj1、ディープコピーが実行された後を示しています。コピーされただけでなくobj1、そこに含まれるオブジェクトもコピーされました。Java Object Serializationディープコピーを作成するために使用できます。残念ながら、このアプローチにもいくつかの問題があります(詳細な例)。

考えられる問題:
clone正しく実装するのは難しい。防御コピー、コピーコンストラクター(@egaga応答として)、または静的ファクトリメソッド
を使用することをお勧めします。

  1. パブリックclone()メソッドがあることはわかっているが、コンパイル時にオブジェクトのタイプがわからないオブジェクトがある場合は、問題が発生します。Javaにはと呼ばれるインターフェースがありますCloneable。実際には、オブジェクトを作成する場合は、このインターフェイスを実装する必要がありますCloneableObject.clone保護されているため、アクセスできるようにするには、パブリックメソッドでオーバーライドする必要があります
  2. 私たちがしようとすると、別の問題が発生する深いコピー複雑なオブジェクトを。仮定しclone()、すべてのメンバーオブジェクト変数の方法も深いコピーをして、これは仮定の危険すぎるです。すべてのクラスでコードを制御する必要があります。

たとえば、org.apache.commons.lang.SerializationUtilsには、serialization(Source)を使用したディープクローンのメソッドがあります。Beanのクローンを作成する必要がある場合は、org.apache.commons.beanutils(ソース)にいくつかのユーティリティメソッドがあります。

  • cloneBean Beanクラス自体がCloneableを実装していない場合でも、使用可能なプロパティのゲッターとセッターに基づいてBeanのクローンを作成します。
  • copyProperties プロパティ名が同じであるすべての場合に、元のBeanから宛先Beanにプロパティ値をコピーします。
134
pacheco 2013-05-03 09:45.

パッケージimport org.apache.commons.lang.SerializationUtils;には次の方法があります。

SerializationUtils.clone(Object);

例:

this.myObjectCloned = SerializationUtils.clone(this.object);
104
Bhasker Tiwari 2010-05-17 23:27.

以下のとおりです。

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
43
WillingLearner 2014-08-16 23:27.

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;
        }
    }
31
Peter 2013-07-10 10:14.

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;
}
}
24
Chrisb 2009-05-16 04:36.

はい、オブジェクトへの参照を作成しているだけです。を実装してCloneableいる場合は、オブジェクトのクローンを作成できます。

オブジェクトのコピーに関するこのwiki記事をチェックしてください。

ここを参照してください:オブジェクトのコピー

14
Teja Maridu 2013-08-01 05:00.

Cloneableクラスに以下のコードを追加します

public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

これを使って clonedObject = (YourClass) yourClassObject.clone();

12
Qamar 2017-01-26 22:50.

これも機能します。モデルを想定

class UserAccount{
   public int id;
   public String name;
}

まずcompile 'com.google.code.gson:gson:2.8.1'アプリに追加> gradle&sync。次に

Gson gson = new Gson();
updateUser = gson.fromJson(gson.toJson(mUser),UserAccount.class);

transientアクセス修飾子の後にキーワードを使用すると、フィールドの使用を除外できます。

注:これは悪い習慣です。また、使用をお勧めしませんCloneableまたはJavaSerializationそれは遅くて壊れています。最高のパフォーマンスを実現するためのコピーコンストラクターを記述します。

何かのようなもの

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を使用してください。品質が必要な場合は、2番目のコピーコンストラクターを使用します。

AndroidStudioでコピーコンストラクターコードジェネレータープラグインを使用することもできます。

11
Jon Bringhurst 2009-05-16 04:35.

clone()あなたがそれを必要とすることになった場合のまともな説明はここにあります...

ここで:clone(Javaメソッド)

10
bruno conde 2009-05-16 04:35.

はい。オブジェクトをディープコピーする必要があります。

10
abbas 2014-07-09 07:14.

ディープクローニングがあなたの答えであり、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 like String 
      // however, in case of non primitive types
      // cloned.setNonPrimitiveType(cloned.getNonPrimitiveType().clone());
      return cloned;
   }
}

あなたはそれをこのように呼ぶでしょう DummyBean dumtwo = dum.clone();

9
Cojones 2011-10-24 06:12.

ディープクローニングユーティリティを使用します。

SomeObjectType copy = new Cloner().deepClone(someObject);

これにより、Javaオブジェクトがディープコピーされます。 https://github.com/kostaskougios/cloning

7
Yishai 2009-05-16 04:33.

これを行うには、何らかの方法でオブジェクトのクローンを作成する必要があります。Javaにはクローン作成メカニズムがありますが、必要がない場合は使用しないでください。コピー作業を行うコピーメソッドを作成してから、次の手順を実行します。

dumtwo = dum.copy();

ここではコピーを達成するための様々な技術上のいくつかのより多くのアドバイスがあります。

6
Tom Hawtin - tackline 2009-05-16 04:43.

明示的にコピーする以外の別のアプローチは、オブジェクトを不変にすることです(nosetまたは他のミューテーターメソッド)。このようにして、問題が発生することはありません。不変性は大きなオブジェクトではより困難になりますが、その反対側は、コヒーレントな小さなオブジェクトとコンポジットに分割する方向にあなたをプッシュすることです。

5
Pierre 2019-09-19 22:29.

egagaのコンストラクターメソッドのコピーの代替。おそらくすでにPOJOを持っているのでcopy()、初期化されたオブジェクトのコピーを返す別のメソッドを追加するだけです。

class DummyBean {
    private String dummyStr;
    private int dummyInt;

    public DummyBean(String dummyStr, int dummyInt) {
        this.dummyStr = dummyStr;
        this.dummyInt = dummyInt;
    }

    public DummyBean copy() {
        return new DummyBean(dummyStr, dummyInt);
    }

    //... Getters & Setters
}

すでに持っていてDummyBean、コピーが必要な場合:

DummyBean bean1 = new DummyBean("peet", 2);
DummyBean bean2 = bean1.copy(); // <-- Create copy of bean1 

System.out.println("bean1: " + bean1.getDummyStr() + " " + bean1.getDummyInt());
System.out.println("bean2: " + bean2.getDummyStr() + " " + bean2.getDummyInt());

//Change bean1
bean1.setDummyStr("koos");
bean1.setDummyInt(88);

System.out.println("bean1: " + bean1.getDummyStr() + " " + bean1.getDummyInt());
System.out.println("bean2: " + bean2.getDummyStr() + " " + bean2.getDummyInt());

出力:

bean1: peet 2
bean2: peet 2

bean1: koos 88
bean2: peet 2

しかし、どちらもうまく機能します。最終的にはあなた次第です...

4
Mahdi Abdi 2014-03-03 03:35.
class DB {
  private String dummy;

  public DB(DB one) {
    this.dummy = one.dummy; 
  }
}
4
A-Droid Tech 2014-12-24 02:46.

コピーするオブジェクトを渡し、必要なオブジェクトを取得します。

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目的のオブジェクトを解析します。

ハッピーコーディング!

3
Jaime Hablutzel 2011-07-26 06:59.

XStreamを使用して、から自動的にディープコピーできます。 http://x-stream.github.io/:

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));

これにより、クローンインターフェイスを実装する必要なしにコピーを作成できます。

2
Amir Hossein Ghasemi 2018-02-04 22:27.
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();
2
tuhin47 2020-05-15 07:16.

gsonオブジェクトを複製するために使用します。

public static <T>T copyObject(Object object){
    Gson gson = new Gson();
    JsonObject jsonObject = gson.toJsonTree(object).getAsJsonObject();
    return gson.fromJson(jsonObject,(Type) object.getClass());
}

私がオブジェクトを持っていると仮定しますperson

Person copyPerson = copyObject(person);

注:パフォーマンスははるかに遅くなります。

1
Noname 2009-05-16 09:49.

メソッドの実装Cloneableと使用を試みることができclone()ます。しかし、あなたは、あなたがしなければならないcloneメソッドを使用する場合-常に上書き-標準によってObjectpublic Object clone()方法を。

1
Lars Bohl 2017-02-06 06:17.

ソースファイルに注釈を追加できる場合は、このような注釈プロセッサまたはコードジェネレータを使用できます。

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();

Related questions

MORE COOL STUFF

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

グッドジョブ、ESPN

グッドジョブ、ESPN

今日のホワイトハウスの記者会見で、報道官のサラ・ハッカビー・サンダースは、スポーツセンターのホストであるイェメル・ヒルのドナルド・トランプに関する最近のツイートについてコメントするよう求められ、大統領と彼の政策を白人至上主義者として説明した。ヒルは彼女のつぶやきのためにESPNによって公に叱責されました。

アマゾンからのこのレミントンツールセールで髪を整える、スタイルを整える、乾かす、または取り除く

アマゾンからのこのレミントンツールセールで髪を整える、スタイルを整える、乾かす、または取り除く

基本的に頭のあらゆる部分から髪の毛を整えたり、ブロードライしたり、まっすぐにしたり、脱毛したりする必要がある場合は、このレミントンゴールドボックスが最適です。今日だけ、Amazonは、すでに人気のあるShortcut Pro Self-HaircutKitやPearlPro Ceramic Flat Ironのように、グルーミングをはるかに簡単にするヘアツールをマークダウンしています。

カナダの元桂冠詩人が、史上最高の文化の盗用でトゥパックとマヤアンジェロウから盗んだ

カナダの元桂冠詩人が、史上最高の文化の盗用でトゥパックとマヤアンジェロウから盗んだ

トゥパックシャクール(ティムモーゼンフェルダー/ゲッティイメージズ); マヤアンジェロウ(マーティンゴッドウィン/ゲッティイメージズ)移動、テイラースウィフト。ケンドールとカイリーは、必要な数の座席を持っています。

テスラは、ハリケーンイルマによる避難を容易にするために、フロリダでの車両の範囲を拡大しています

テスラは、ハリケーンイルマによる避難を容易にするために、フロリダでの車両の範囲を拡大しています

写真:Tesla Motorsフロリダに住んでいて、Tesla Model S、Model X 60、またはModel 60Dを使用している場合、車の自律性は50 km(約30マイル)高くなります。これは失敗ではなく、ハリケーンイルマによる避難作業を容易にするために会社自身が命じた自治権の一時的な延長です。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

投資ノート:Bioscout AU$300万シード

投資ノート:Bioscout AU$300万シード

Bioscoutは、農家を運転席に置くという使命を負っています。Artesian(GrainInnovate)やUniseedと並んで、最新のシードラウンドでチームを支援できることをうれしく思います。問題真菌症による重大な作物の損失は、農民にとって試練であることが証明されています。

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

遠隔医療は、パンデミック後の時代では新しいものではなく、時代遅れの分野でもありません。しかし、業界を詳しく見ると、需要と供給の強力な持続可能性と、米国で絶え間ない革命となる強力な潜在的成長曲線を示しています。

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

2021年は、世界的なベンチャーキャピタル(VC)の資金調達にとって記録的な年でした。DealStreetAsiaによると、東南アジアも例外ではなく、この地域では年間で記録的な25の新しいユニコーンが採掘されました。

ムーアの法則を超えて

ムーアの法則を超えて

計算に対する私たちの欲求とムーアの法則が提供できるものとの間には、指数関数的に増大するギャップがあります。私たちの文明は計算に基づいています—建築と想像力の現在の限界を超える技術を見つけなければなりません。

Language