- PR -

多重配列のディープコピー方法

投稿者投稿内容
モンプチ
常連さん
会議室デビュー日: 2004/06/03
投稿数: 28
投稿日時: 2004-06-14 11:12
おはようございます。
三度失礼します。

多重配列のディープコピーは、どのように行えばよろしいのでしょうか?
以下のように行うと、シャローコピーとなってしまい、困っております。


// 集計用arraylistの作成
iArea_NT_ItemTotal = new int[iNT][][];

for(int i=0; i < iNT; i++)
{
// 配列2・3列目の構造は、iItem_Listと同様とする
iArea_NT_ItemTotal[i] = iItem_List;
}

// 集計用arraylistの格納値を初期化する(iItem_Listの値が格納されているため)
for (int i=0; i<iArea_NT_ItemTotal.length ;i++)
{
System.out.println("第" + i + "回目");

for (int is=0; is < iArea_NT_ItemTotal[i].length ;is++)
{
for (int it=0; it < iArea_NT_ItemTotal[i][is].length ;it++)
{

iArea_NT_ItemTotal[i][is][it] = 0;
}
}
}

// コピー元まで「0」になってしまう
for (int i=0; i<iItem_List.length ;i++)
{
for (int is=0; is < iItem_List[i].length ;is++)
{
System.out.println(iItem_List[i][is]);
}
}

コピー元と各配列の格納数を一致させたいのです。
よき方法ありましたら、御教授願います。

たびたび申し訳御座いません。
どうかどうかよろしくお願い致します。
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2004-06-14 12:36
引用:
コード:

for(int i=0; i < iNT; i++)
{
// 配列2・3列目の構造は、iItem_Listと同様とする
iArea_NT_ItemTotal[i] = iItem_List;
}



ここが、シャローコピーです。
以下のように、ハードコピーしてください
コード:

for(int i=0; i < iNT; i++) {
// 配列2・3列目の構造は、iItem_Listと同様とする
int[][] itemList = new int[iItem_List.length][];
iArea_NT_ItemTotal[i] = itemList;

for (int j = 0; j < itemList.length; ++j) {
int[] items = new int[itemList[j].length];
itemList[j] = items;
    System.arraycopy(itemList[j], 0, items, 0, items.length);
}
}




[ メッセージ編集済み 編集者: かずくん 編集日時 2004-06-14 12:38 ]
モンプチ
常連さん
会議室デビュー日: 2004/06/03
投稿数: 28
投稿日時: 2004-06-14 13:03
「かずくん」様、御返事有難う御座います。
再度助けて頂き、深く感謝致しております。

正直、これは自分には書けませんでした。
教えて頂けなかったら、路頭に迷っていたと思います。

参考にさせて頂き、勉強致します。
本当に有難う御座いました。
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2004-06-14 13:49
私の場合、ディープクローンはこういうメソッド一つで済ませてしまうこと
が多いですね。引数がプリミティブ値の多重配列でも問題ありません。
遅いかもしれませんが、それが問題になるような用件はあまり無いでしょう。

コード:
public static Serializable deepClone(Serializable src)
 throws IOException,ClassNotFoundException{

 ByteArrayOutputStream bout = new ByteArrayOutputStream();
 ObjectOutputStream oout = new ObjectOutputStream(bout);
 oout.writeObject(src);
 oout.flush();
		
 byte[] serialized = bout.toByteArray();
	
 ByteArrayInputStream bin = new ByteArrayInputStream(serialized);
 ObjectInputStream oin = new ObjectInputStream(bin);
 return (Serializable)oin.readObject();
}


モンプチ
常連さん
会議室デビュー日: 2004/06/03
投稿数: 28
投稿日時: 2004-06-14 18:58
「シュン」様、御返事有難う御座います。

せっかく教えて頂いた処理内容が理解できません。
すいません。
週末に調べて、なんとか理解させて頂きます。

御返事遅れてしまい失礼致しました。
皆様に御迷惑かけぬよう努力致しますので、今後ともよろしくお願い致します。
有難う御座いました。
おばけ
ぬし
会議室デビュー日: 2002/11/14
投稿数: 609
お住まい・勤務地: 東京都江東区
投稿日時: 2004-06-15 01:18
シュンさんの書かれているシリアライズによるディープコピー、実は今やっている案件で使っています。
最初見た時は、私もこういうアイデアには気付かなかったもので、「おお!すごい!!」と
かなり感動しました。

ただ、パフォーマンスチューニングでプロファイルを取ったら、シリアライズ/デシリアライズで行われる
オブジェクトのI/Oはどうやら遅いようですね。一般的に言ってこれらのメソッドは遅いのでしょうか?
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2004-06-15 10:43
>モンプチさん
Javaにはオブジェクトシリアライゼーション(JavaDoc上では直列化と訳されています。
Javaをはじめたころは「直列化って何?」と思ったものです^^;)という機構がありま
して、オブジェクトをストリームに流し込んだり、ストリームから読み出したバイト
アレイからオブジェクトを再構成する作業を、java.ioパッケージのAPIが内部でやって
くれるのです。
オブジェクトをファイルに保存したり、ソケット経由でリモートプロセスに渡したりする
ために、良く使われます。それを利用した一種の手抜きです^^;

Javaでは、配列は特殊なオブジェクトでしかありません。一般のSerializableオブジェク
ト同様直列化することが可能です。


>おばけさん
ベタベタにオブジェクト参照を再帰で追っていって一オブジェクトずつ直列化していく
ので、理屈からしても早いはずが無いですよね。ディープコピーを生成したいときは大抵
参照関係のツリー構造が深いですし。

自分で書いておいてなんですが、私の場合このようなメソッドを実際に利用することは、
あまり無いのです。
私の場合、オブジェクトのディープクローンを生成しなければならなくなった時点で、設
計の欠陥を疑います。ImmutableやCopy on writeの考え方を利用して、できる限りコピ
ーの生成は遅延させ、可能ならば参照の共有で済ますつくりを考えます。そして、大抵それ
で済んでしまいます^^;
びしばし
大ベテラン
会議室デビュー日: 2002/03/13
投稿数: 181
投稿日時: 2004-06-15 13:51
>シリアライズを利用

シュンさんのように、メリットもデメリットもわかってて使われる分にはいいのですが、
わかっていない後輩とかがこういうコードを書いたら作り直させますね。

むやみにクラスを Serializable にすることの危険性などについては Joshua Bloch が書いてますね。

Effective Java プログラミング言語ガイド http://www.amazon.co.jp/exec/obidos/ASIN/4894714361/bishibashi-22

スキルアップ/キャリアアップ(JOB@IT)