プロが教えるわが家の防犯対策術!

現在、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が削除されたにも関わらず何とも変化がなくて、一応目的の動きはしています。

 シャローコピーの場合、参照元に何か変化があるとコピー先のものまで変化してしまうようなので、これは、ディープコピーということでいいんでしょうか?
  

A 回答 (4件)

落ち着いて考えれば分かるはずです。



とりあえず言いたいことを整理させてもらいますが

・「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によってのみ行われます。
それさえ押さえていれば、今回のような質問には
いたらなかったのではないかなぁと思います。
    • good
    • 0

こんにちは、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
    • good
    • 0

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には影響ありません。
    • good
    • 0

言葉の定義は、良く分からないので、


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
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!