『データ構造とJava集合フレームワーク第3版』読書ノート(五)浅複製(shallow copy)と深複製
今日はArrayListを勉強します
一、浅いコピー
そのレプリケーションコンストラクション関数とclone()関数は、いずれも浅いレプリケーション(shallow copy)、すなわちレプリケーションオブジェクトの参照です.反対に深いレプリケーションは、レプリケーションオブジェクト自体です.
1,複製構造関数ArrayList(Collectionc)
c中の要素のコピーを含む新しいArrayListオブジェクトが得られた.ただし、集合cの要素の本質は、オブジェクトではなく参照であることに注意してください.参照されたオブジェクト自体はコピーされていません.
2,clone()関数もそうです
例:
temp 2の0番目のエレメント参照StringBufferオブジェクトは、temp 1の0番目のエレメント参照と同じStringBufferオブジェクトに変更されました.
つまり、2つの要素が同じメモリを指しているのか、同じメモリを指しているのか.だからtemp 1もtemp 2も「yesno」を保存しました
でも
StringBufferオブジェクトは可変ですが、Stringオブジェクトは可変ではありません.Stringオブジェクトが作成されると、そのオブジェクトの内容は変更できません.したがって、第2セグメントプログラムのtemp 2の0番目の要素は、実際には新しいStringオブジェクト「no」を指し、temp 1の0番目の要素は「yes」を参照する.
3, java.util.list.addAll()メソッドも同様に浅いレプリケーションです
4,下のこのlistを1つの要素addごとに遍歴する方法も浅いコピーで、これは比較的に間違いやすいです
s
rcListの0番目の要素に格納されるPersonオブジェクトの値は変更可能である.StringBufferに似ています
5,Collectionsのcopy(List desc,List src)メソッドも浅いコピーです.下の文章の言い方はjavaの中で深くコピーして伸ばすCollections.copyの使用を誤っています
文章は深いコピーと呼ばれ、2つのlistの各要素が同じメモリではないことを示しています.コードは次のとおりです.
下のように書くと配列境界異常が放出されます
ArrayListのcapacity(収容能力サイズ)は指定(最適指定)できますが、初期化時のsizeのサイズは常に0にデフォルト設定され、addやremoveなどの関連操作を行う場合にのみsizeのサイズが変化します.
だからdes 1.size()は0です.3はこのリストの収容能力が3であることを示し,des 1に3つの要素があるわけではない.しかし、copy()を行う場合、まずdesc 1のsizeとsrc 1のsizeサイズを比較し、desc 1のsizeがsrc 1のsizeより大きいか等しい場合にのみコピーを行い、そうでない場合はIndexOutOfBoundsException異常を投げ出す.
実際の状況:
まだ浅いレプリケーションです.この文書の著者を誤導したのはStringオブジェクトが変更できないためであり,clone法に倣って例を挙げるとStringBufferに変更すると実質的に浅い複製であることがわかる.
二、深く複製する方法
シーケンス化
参考文章:頼りないjava.util.Listディープコピー方法
三、浅いレプリケーションと別名は違います.
エイリアスは、同じオブジェクトに対する別の参照変数です.例えばArrayList sameList=myList;
sameListとmyListは同じArrayListオブジェクトの参照変数であり、myListオブジェクトへの変更、すなわちsameListオブジェクトへの変更である.
上記の浅い複製方法は、
はtemp 2がtemp 1の要素をコピーし、これらの要素は参照変数であり、コピーされた要素は元の要素と同じメモリを指します.temp 1の要素参照オブジェクトの変更はtemp 2の要素参照オブジェクトに影響します.temp 1の要素を新しいオブジェクトに再参照し、新しいメモリを指すだけで、temp 2の要素は元のオブジェクトを参照し、元のメモリを指します.
一、浅いコピー
そのレプリケーションコンストラクション関数とclone()関数は、いずれも浅いレプリケーション(shallow copy)、すなわちレプリケーションオブジェクトの参照です.反対に深いレプリケーションは、レプリケーションオブジェクト自体です.
1,複製構造関数ArrayList(Collectionc)
c中の要素のコピーを含む新しいArrayListオブジェクトが得られた.ただし、集合cの要素の本質は、オブジェクトではなく参照であることに注意してください.参照されたオブジェクト自体はコピーされていません.
2,clone()関数もそうです
例:
ArrayList<StringBuffer> temp1=new ArrayList<StringBuffer>();
StringBuffer x=new StringBuffer("yes");
temp1.add(x);
ArrayList<StringBuffer> temp2=(ArrayList)temp1.clone();
temp2.set(0,x.append("no"));
temp 2の0番目のエレメント参照StringBufferオブジェクトは、temp 1の0番目のエレメント参照と同じStringBufferオブジェクトに変更されました.
つまり、2つの要素が同じメモリを指しているのか、同じメモリを指しているのか.だからtemp 1もtemp 2も「yesno」を保存しました
でも
ArrayList<String> temp1=new ArrayList();
String x="yes";temp1.add(x);ArrayList<String> temp2=(ArrayList)temp1.clone();
temp2.set(0,"no");
StringBufferオブジェクトは可変ですが、Stringオブジェクトは可変ではありません.Stringオブジェクトが作成されると、そのオブジェクトの内容は変更できません.したがって、第2セグメントプログラムのtemp 2の0番目の要素は、実際には新しいStringオブジェクト「no」を指し、temp 1の0番目の要素は「yes」を参照する.
3, java.util.list.addAll()メソッドも同様に浅いレプリケーションです
4,下のこのlistを1つの要素addごとに遍歴する方法も浅いコピーで、これは比較的に間違いやすいです
class Person implements Serializable{
private int age;
private String name;
public Person(){};
public Person(int age,String name){
this.age=age;
this.name=name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String toString(){
return this.name+"-->"+this.age;
}
}
List<Person> destList=new ArrayList<Person>(srcList.size());
for(Person p : srcList){
destList.add(p);
}
printList(destList);
srcList.get(0).setAge(100);
printList(destList);
s
rcListの0番目の要素に格納されるPersonオブジェクトの値は変更可能である.StringBufferに似ています
5,Collectionsのcopy(List desc,List src)メソッドも浅いコピーです.下の文章の言い方はjavaの中で深くコピーして伸ばすCollections.copyの使用を誤っています
文章は深いコピーと呼ばれ、2つのlistの各要素が同じメモリではないことを示しています.コードは次のとおりです.
List<String> src = new ArrayList<String>();
src.add("111");
src.add("222");
src.add("333");
src.add("444");
List<String> dic = new ArrayList<String>(Arrays.asList(new String[src
.size()]));
Collections.copy(dic, src);
注意:Arraysを使用する必要があります.asListメソッドpublic static <T> List<T> asList(T... a) 。
下のように書くと配列境界異常が放出されます
List des1 = new ArrayList( 3 );
Collections.copy(des1,src1);
ArrayListのcapacity(収容能力サイズ)は指定(最適指定)できますが、初期化時のsizeのサイズは常に0にデフォルト設定され、addやremoveなどの関連操作を行う場合にのみsizeのサイズが変化します.
だからdes 1.size()は0です.3はこのリストの収容能力が3であることを示し,des 1に3つの要素があるわけではない.しかし、copy()を行う場合、まずdesc 1のsizeとsrc 1のsizeサイズを比較し、desc 1のsizeがsrc 1のsizeより大きいか等しい場合にのみコピーを行い、そうでない場合はIndexOutOfBoundsException異常を投げ出す.
実際の状況:
まだ浅いレプリケーションです.この文書の著者を誤導したのはStringオブジェクトが変更できないためであり,clone法に倣って例を挙げるとStringBufferに変更すると実質的に浅い複製であることがわかる.
二、深く複製する方法
シーケンス化
public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(src);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in = new ObjectInputStream(byteIn);
@SuppressWarnings("unchecked")
List<T> dest = (List<T>) in.readObject();
return dest;
}
参考文章:頼りないjava.util.Listディープコピー方法
三、浅いレプリケーションと別名は違います.
エイリアスは、同じオブジェクトに対する別の参照変数です.例えばArrayList sameList=myList;
sameListとmyListは同じArrayListオブジェクトの参照変数であり、myListオブジェクトへの変更、すなわちsameListオブジェクトへの変更である.
上記の浅い複製方法は、
ArrayList<E> temp2=(ArrayList)temp1.clone();
はtemp 2がtemp 1の要素をコピーし、これらの要素は参照変数であり、コピーされた要素は元の要素と同じメモリを指します.temp 1の要素参照オブジェクトの変更はtemp 2の要素参照オブジェクトに影響します.temp 1の要素を新しいオブジェクトに再参照し、新しいメモリを指すだけで、temp 2の要素は元のオブジェクトを参照し、元のメモリを指します.