- 締切済み
javaにおけるシャローコピーとディープコピー
現在、javaによるプログラミングを行っています。 シャローコピーとディープコピーについてお聞きしたく質問させていただきます。 例えば、あるクラスDataをインスタンス化して、instance という名前のArrayListを作ったとします。 class Data{ int x; int y; int z; } それで、insというArrayListを別のData型のインスタンス化されたins2という型のArrayListにコピーしたいんですが。 現在は、 ins2.add(ins.get(~~)); といった感じで書いていて、処理の関係上途中、コピー元のinsをremove allで全部削除してしまっていたりしているんですが、ins2の中身は、insが削除されたにも関わらず何とも変化がなくて、一応目的の動きはしています。 シャローコピーの場合、参照元に何か変化があるとコピー先のものまで変化してしまうようなので、これは、ディープコピーということでいいんでしょうか?
- みんなの回答 (4)
- 専門家の回答
みんなの回答
- OKbokuzyo
- ベストアンサー率43% (130/296)
落ち着いて考えれば分かるはずです。 とりあえず言いたいことを整理させてもらいますが ・「ins」「ins2」はArrayList型の変数。 ・「ins」にはData型のインスタンスを入れている。 ・「ins2」に「ins」から取得したData型のインスタンスを入れた。 ・「ins」の中身を消しているのに同じインスタンスを見ているはずの 「ins2」の中身は消えていない。⇒ナゼ?? ということで良いですか? insのインスタンスが管理しているのは 「Data型のインスタンス」ではなく 「Data型のインスタンスへの参照情報」です。 早い話が、insはData型の参照変数を 配列形式に持っているだけです。 ins.get(~)によって返されるのも 「Data型のインスタンス」ではなく、 「Data型のインスタンスへの参照情報」です。 つまりins2が持っているのも 「Data型のインスタンスへの参照情報」です。 ここで、ins.removeAllとすると 消去されるのは「Data型のインスタンス(実体)」ではなく、 insの持つ「Data型のインスタンスへの参照情報」です。 「Data型のインスタンス(実体)」が消去されているわけではないので ins2の持つ「Data型のインスタンスへの参照情報」はまだ有効なわけです。 すなわち、質問者様の状況はData型のインスタンスが ディープコピーされているわけではないです。 そもそも、Javaというものは 開発者がインスタンスを直接消去したりすることはできません。 必ず、変数(参照情報)を介する仕組みになっており インスタンスの消去はGCによってのみ行われます。 それさえ押さえていれば、今回のような質問には いたらなかったのではないかなぁと思います。
- tom11
- ベストアンサー率53% (134/251)
こんにちは、kmeeさん、ディープコピーと言うのは 以下のような、結果のコードですかね??? class Data implements Cloneable{ int x,y; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public class arraylist_clone { public arraylist_clone() { ArrayList<Data> ar1,ar2,ar3,ar4; ar1= new ArrayList<Data>(); Data [] d = new Data[5]; for(int x=0;x<5;x++){ d[x]=new Data(); d[x].x=x+1; d[x].y=x*10; ar1.add(d[x]); } ar2=ar1; ar3=(ArrayList<Data>) ar1.clone(); ar4=deepcopy(ar1); System.out.println("元来"); show(ar1); ar1.remove(4); ar1.remove(2); System.out.println("参照代入"); show(ar2); System.out.println("シャローコピー"); show(ar3); ar3.get(1).x=100; ar3.get(1).y=200; ar1.get(0).x=500; ar1.get(0).y=600; System.out.println("a1"); show(ar1); System.out.println("a3"); show(ar3); System.out.println("a4"); show(ar4); } /** * @param args the command line arguments */ public static void main(String[] args) { new arraylist_clone(); // TODO code application logic here } private void show(ArrayList<Data> ar1) { for(Iterator <Data> it=ar1.listIterator();it.hasNext();){ Data d = it.next(); System.out.println(d.x+" "+d.y); } } private ArrayList<Data> deepcopy(ArrayList<Data> ar1) { Data d = new Data(); ArrayList<Data> ad = new ArrayList<Data>(); for(Iterator<Data> it = ar1.iterator();it.hasNext();){ try { ad.add((Data) it.next().clone()); } catch (CloneNotSupportedException ex) { Logger.getLogger(arraylist_clone.class.getName()).log(Level.SEVERE, null, ex); } } return ad; } } 実行結果 元来 1 0 2 10 3 20 4 30 5 40 参照代入 1 0 2 10 4 30 シャローコピー 1 0 2 10 3 20 4 30 5 40 a1 500 600 100 200 4 30 a3 500 600 100 200 3 20 4 30 5 40 a4 1 0 2 10 3 20 4 30 5 40
- kmee
- ベストアンサー率55% (1857/3366)
ins= →a0[ →d0, →d1,... ] だとします。→a0はArrayListの、→d0,→d1はDataのインスタンスへの参照です。 シャローコピーしたins2は次のようになります ins2= →a2[ →d0, →d1,... ] つまり、中身がa0と同じ新しい ArrayListのインスタンスができます。 ここで、insを空にしても、影響するのはa0なので、a2には影響ありません。 参照元に変化、というのは、たとえば ins[0].x=0 などとして、dXに変更があった場合、同じインスタンスを参照しているins2も変化するということです。 (正確には,ins2自体は変化しないが、参照先が変化しているので、ins2[0].xなどとして取り出す値が変化する) 対して、 ディープコピーした ins3は次のようになります ins3= →a3[ →d'0, →d'1,... ] d'XはdXと中身は一緒ですが別のインスタンスです。dXに変更があっても、d'Xには影響ありません。
- tom11
- ベストアンサー率53% (134/251)
言葉の定義は、良く分からないので、 APIにある、シャローコピーと、代入のリストと結果を 載せてみました。 class Data{ int x,y; } public class arraylist_clone { public arraylist_clone() { ArrayList<Data> ar1,ar2,ar3; ar1= new ArrayList<Data>(); Data [] d = new Data[10]; for(int x=0;x<10;x++){ d[x]=new Data(); d[x].x=x+1; d[x].y=x*10; ar1.add(d[x]); } ar2=ar1; ar3=(ArrayList<Data>) ar1.clone(); System.out.println("元来"); show(ar1); ar1.remove(5); ar1.remove(2); System.out.println("参照代入"); show(ar2); System.out.println("シャローコピー"); show(ar3); } /** * @param args the command line arguments */ public static void main(String[] args) { new arraylist_clone(); // TODO code application logic here } private void show(ArrayList<Data> ar1) { for(Iterator <Data> it=ar1.listIterator();it.hasNext();){ Data d = it.next(); System.out.println(d.x+" "+d.y); } } } 結果 元来 1 0 2 10 3 20 4 30 5 40 6 50 7 60 8 70 9 80 10 90 参照代入 1 0 2 10 4 30 5 40 7 60 8 70 9 80 10 90 シャローコピー 1 0 2 10 3 20 4 30 5 40 6 50 7 60 8 70 9 80 10 90