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

「水曜日」シーズン1の中心には大きなミステリーがあります

「水曜日」シーズン1の中心には大きなミステリーがあります

Netflixの「水曜日」は、典型的な10代のドラマ以上のものであり、実際、シーズン1にはその中心に大きなミステリーがあります.

ボディーランゲージの専門家は、州訪問中にカミラ・パーカー・ボウルズが輝くことを可能にした微妙なケイト・ミドルトンの動きを指摘しています

ボディーランゲージの専門家は、州訪問中にカミラ・パーカー・ボウルズが輝くことを可能にした微妙なケイト・ミドルトンの動きを指摘しています

ケイト・ミドルトンは、州の夕食会と州の訪問中にカミラ・パーカー・ボウルズからスポットライトを奪いたくなかった、と専門家は言う.

一部のファンがハリー・スタイルズとオリビア・ワイルドの「非常に友好的な」休憩が永続的であることを望んでいる理由

一部のファンがハリー・スタイルズとオリビア・ワイルドの「非常に友好的な」休憩が永続的であることを望んでいる理由

一部のファンが、オリビア・ワイルドが彼女とハリー・スタイルズとの間の「難しい」が「非常に友好的」な分割を恒久的にすることを望んでいる理由を見つけてください.

エリザベス女王の死後、ケイト・ミドルトンはまだ「非常に困難な時期」を過ごしている、と王室の専門家が明らかにする 

エリザベス女王の死後、ケイト・ミドルトンはまだ「非常に困難な時期」を過ごしている、と王室の専門家が明らかにする&nbsp;

エリザベス女王の死後、ケイト・ミドルトンが舞台裏で「非常に困難な時期」を過ごしていたと伝えられている理由を調べてください.

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セント ヘレナ島のジェイコブズ ラダーは 699 段の真っ直ぐ上る階段で、頂上に到達すると証明書が発行されるほどの難易度です。

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

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

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

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

Total War:Warhammer:Kotakuレビュー

Total War:Warhammer:Kotakuレビュー

私はこのゲームを嫌う準備ができていました。先週の前に、Total War:Warhammerについての私の考えがありました:それでもここに私は、私の手にある完成品であり、私は変わった男です。

涙の道:軍事化された帝国主義勢力がスタンディングロックキャンプを占領

涙の道:軍事化された帝国主義勢力がスタンディングロックキャンプを占領

スタンディングロックスー族のメンバーと水の保護者は、ノースダコタ州のスタンディングロックにあるオセティサコウィンキャンプを去ります。(Twitter経由のCNNスクリーンショット)火と煙がスカイラインを覆い、スタンディングロックスー族のメンバーと水の保護者が、聖なるものを守りながら建てた家、オセティサコウィン(セブンカウンシルファイアーズ)キャンプから行進し、太鼓を打ち、歌い、祈りました。ダコタアクセスパイプラインとしても知られる「ブラックスネーク」からの土地。

シアーズとKマートはイヴァンカ・トランプの商品を自分たちで取り除いています

シアーズとKマートはイヴァンカ・トランプの商品を自分たちで取り除いています

写真:APシアーズとKマートは、イヴァンカ・トランプのトランプホームアイテムのコレクションも、誰も購入したくないために削除しました。シアーズとKマートの両方の親会社であるシアーズホールディングスは、土曜日のABCニュースへの声明で、彼らが気にかけていると辛抱強く説明しましたトランプラインを売り続けるにはお金を稼ぐことについてあまりにも多く。

ポテトチップスでたった10分でスペインのトルティーヤを作る

ポテトチップスでたった10分でスペインのトルティーヤを作る

伝統的なスペインのトルティーヤは通常、オリーブオイルで柔らかくなるまで調理されたポテトから始まります(30分以上かかる場合があります)が、ケトルで調理されたポテトチップスの助けを借りてわずか10分でテーブルに置くことができます。上のビデオはすべてがバラバラにならないように裏返す方法を含め、レシピ全体を説明しますが、必要なのは4〜5個の卵と3カップのケトルチップスだけです。

ケイト・ミドルトンとウィリアム王子は、彼らが子供たちと行っているスパイをテーマにした活動を共有しています

ケイト・ミドルトンとウィリアム王子は、彼らが子供たちと行っているスパイをテーマにした活動を共有しています

ケイト・ミドルトンとウィリアム王子は、子供向けのパズルの本の序文を書き、ジョージ王子、シャーロット王女、ルイ王子と一緒にテキストを読むと述べた.

事故で押しつぶされたスイカは、動物を喜ばせ水分補給するために野生生物保護団体に寄付されました

事故で押しつぶされたスイカは、動物を喜ばせ水分補給するために野生生物保護団体に寄付されました

Yak's Produce は、数十個のつぶれたメロンを野生動物のリハビリ専門家であるレスリー グリーンと彼女のルイジアナ州の救助施設で暮らす 42 匹の動物に寄付しました。

デミ・ロヴァートは、新しいミュージシャンのボーイフレンドと「幸せで健康的な関係」にあります: ソース

デミ・ロヴァートは、新しいミュージシャンのボーイフレンドと「幸せで健康的な関係」にあります: ソース

8 枚目のスタジオ アルバムのリリースに向けて準備を進めているデミ ロヴァートは、「スーパー グレート ガイ」と付き合っている、と情報筋は PEOPLE に確認しています。

Plathville の Kim と Olivia Plath が数年ぶりに言葉を交わすことへようこそ

Plathville の Kim と Olivia Plath が数年ぶりに言葉を交わすことへようこそ

イーサン プラスの誕生日のお祝いは、TLC のウェルカム トゥ プラスビルのシーズン 4 のフィナーレで、戦争中の母親のキム プラスと妻のオリビア プラスを結びつけました。

仕事の生産性を高める 8 つのシンプルなホーム オフィスのセットアップのアイデア

仕事の生産性を高める 8 つのシンプルなホーム オフィスのセットアップのアイデア

ホームオフィスのセットアップ術を極めよう!AppExert の開発者は、家族全員が一緒にいる場合でも、在宅勤務の技術を習得しています。祖父や曽祖父が共同家族で暮らしていた頃の記憶がよみがえりました。

2022 年、私たちのデジタル ライフはどこで終わり、「リアル ライフ」はどこから始まるのでしょうか?

20 年前のタイムトラベラーでさえ、日常生活におけるデジタルおよびインターネットベースのサービスの重要性に驚くことでしょう。MySpace、eBay、Napster などのプラットフォームは、高速化に焦点を合わせた世界がどのようなものになるかを示してくれました。

ニューロマーケティングの秘密科学

ニューロマーケティングの秘密科学

マーケティング担当者が人間の欲望を操作するために使用する、最先端の (気味が悪いと言う人もいます) メソッドを探ります。カートをいっぱいにして 3 桁の領収書を持って店を出る前に、ほんの数点の商品を買いに行ったことはありませんか? あなたは一人じゃない。

地理情報システムの日: GIS 開発者として学ぶべき最高の技術スタック

地理情報システムの日: GIS 開発者として学ぶべき最高の技術スタック

私たちが住んでいる世界を確実に理解するには、データが必要です。ただし、空間参照がない場合、このデータは地理的コンテキストがないと役に立たなくなる可能性があります。

Language