web-dev-qa-db-ja.com

Javaでは、浅いコピーとは何ですか?

Java.util.Calendar.clone()は、「...同じプロパティを持つ新しいカレンダー」を返し、「このカレンダーの浅いコピー」を返します。

これは here SOで答えられたように浅いコピーではないようです。その質問にはlanguage-agnostic、Javaは言語に依存しない定義に従っていないようです。言語にとらわれない構造だけでなく、構造と要素がこの新しいオブジェクトにコピーされることに気付きました。

Javaでは、浅いコピーとは何ですか?

Javaディープコピー(存在する場合)とはどう違いますか?

49
Will

浅いコピーは、クラス内の参照の値をコピーするだけです。ディープコピーは値をコピーします。与えられた:

_class Foo {
  private Bar myBar;
  ...
  public Foo shallowCopy() {
    Foo newFoo = new Foo();
    newFoo.myBar = myBar;
    return newFoo;
  }

  public Foo deepCopy() {
    Foo newFoo = new Foo();
    newFoo.myBar = myBar.clone(); //or new Bar(myBar) or myBar.deepCopy or ...
    return newFoo;
  }
}

Foo myFoo = new Foo();  
Foo sFoo = myFoo.shallowCopy();  
Foo dFoo = myFoo.deepCopy();  

myFoo.myBar == sFoo.myBar => true  
myFoo.myBar.equals(sFoo.myBar) => true  
myFoo.myBar == dFoo.myBar => **false**  
myFoo.myBar.equals(dFoo.myBar) => true  
_

この場合、浅いコピーには同じ参照(_==_)があり、深いコピーには同等の参照(.equals())のみがあります。

浅くコピーされた参照の値に変更が加えられた場合、同じ参照を共有するため、コピーはその変更を反映します。深くコピーされた参照の値に変更が加えられた場合、同じ参照を共有しないため、コピーはその変更を反映しません。

C-ism

_int a = 10; //init
int& b = a; //shallow - copies REFERENCE
int c = a;  //deep - copies VALUE
++a;
_

結果:

_a is 11  
*b is 11  
c is 10
_
73
KitsuneYMG

浅いコピーは、同じメモリ位置への単なるポインタのセットです。実際には、実際のコピーは作成されないため、メモリ使用量は低くなります。

ディープコピーの場合、メモリセグメントの正確なコピーが作成され、ポインタが新しいメモリ位置に設定されます。したがって、この場合、理論的にはメモリ消費量は2倍になるはずです。

浅いコピーはオブジェクトへの参照ポインタのコピーであり、深いコピーはオブジェクト自体のコピーです。 Javaでは、オブジェクトはバックグラウンドで保持されます。オブジェクトを扱うときに通常操作するのはポインターです。変数名は、オブジェクトのメモリ空間を指します。ある変数を別の変数と等しく設定すると、浅いコピーが作成されます。

Object B = A;

オブジェクトAのプロパティを取得し、それらを新しいオブジェクトBに入れることで、ディープコピーを作成できます。

Object B = new Object(A.getProperty1(), A.getProperty2()...);

これは、浅いコピーを作成してタスクを実行すると、オブジェクトのすべての浅いコピーに影響するという点で、プログラムの動作に影響します。ディープコピーに変更を加えた場合、そのコピーのみが影響を受けます。これがあなたにとって十分に詳細であることを願っています。

5
mnuzzo

1.6ドキュメントドキュメントCalendar.cloneは「このオブジェクトのコピーを作成して返します」。 Object.cloneで指定されたリテラルの浅いコピーは意味がありません。 Javaは、かなり典型的な意味で「浅いコピー」という用語を使用します。

ドキュメントの間違いのようです。 AndroidのCalendar.cloneメソッドが「浅いコピー」の典型的な定義(Javaまたはその他))にどのように適合するかはわかりません。

2
jsight

このドキュメントはどこで入手できますか?

公式のJava Java.Sun.comの6つのドキュメントは、オブジェクトのコピーを返す Calendar.clone() を持っています。浅いことは言及していません。

より一般的には、Javaの浅いコピーは、新しいオブジェクト参照を取得しますが、新しいオブジェクトは元のデータへの参照を(直接的または間接的に)保持するものです。

例えば:

class MyClass{
  private List<Integer> innerList;

  public MyClass(List<Integer> list) { innerList = list; }

  //Some code...

  public Object clone(){
    return new MyClass(innerList);
  }
}

clone()で浅いコピーを返します。

1
Kevin Montrose

浅いコピーは、オブジェクト参照をターゲット参照にコピーするだけです。ヒープ上に新しいオブジェクトは作成されません。デフォルトでは、Javaはclone()関数を使用して浅いクローンを作成します。

ヒープ上に新しいオブジェクトを取得するには、シリアライゼーションとデシリアライゼーションによって実装できるディープクローンを実行する必要があります。

1
Akanksha

まず、ArraysのメソッドcopyOfを使用するため、1次元配列について説明している場合、ArrayListのJavadocは多少間違っています。そのため、clone()は少なくとも1.5以降、1次元のコピーを返します(これ以上テストしませんでした)。それが、Javaで「浅い」という意味です:1次元

詳細はこちらをご覧ください: http://www.javapractices.com/topic/TopicAction.do?Id= 。したがって、clone()は浅いコピーではありません! 1次元配列の実際の浅いコピーが必要な場合は、それを参照するだけです。

Array a = new Array();
Array b = a;                    //a is only a shallow copy, Nice for synchronisation

Javaの配列はJavaは値渡しを行うが、配列の値はポインタのみであるため、注意が必要です!コンテナ配列(またはArrayList)のclone()は値のみをコピーしないため、配列(またはArrayLists)内で配列を使用するといくつかの問題が発生します。それらの参照!したがって、配列に配列を入れるべきではなく、配列内のオブジェクトのみを扱うべきです!

また、Javadocは時々理解するのが難しいので、テストを試してみてください...

楽しむ!

0
mark

浅いコピーでは、クローンオブジェクトにはプリミティブ値のコピーがありますが、オブジェクト参照は元のコピーと同じオブジェクトを参照します。浅いコピーには重大な欠点があり、クローンオブジェクトと元のコピーは同じアドレスオブジェクトを参照します。クローンオブジェクトがアドレスオブジェクトに加える変更は、元のコピーにも反映されますが、これは望ましくない動作です。本当に欲しかったのは、ユーザーオブジェクトの2つのコピーです。ディープコピーは、この種の状況に対処するために役立ちます。

ディープコピーは、プリミティブ値だけでなく、オブジェクト参照のコピーも作成します。

あなたはここでこれに関する実際の例を見ることができます: https://codingninjaonline.com/2017/11/09/deep-vs-shallow-copy/

0
pndey

浅いコピー:このクローンでは、クローンオブジェクトへの変更はすべて元のオブジェクトにも反映されます。

ディープコピー:このクローンでは、個別のクローンメモリが割り当てられます。つまり、クローンオブジェクトへの変更は、元のオブジェクトには反映されません。

0
Neeraj