質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

4回答

3425閲覧

javaでオブジェクト型の配列をSystem.arraycopyした時の動作が理解できません

TK_0831

総合スコア6

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

1クリップ

投稿2018/08/16 04:22

前提・実現したいこと

現在javaについて学習を進めているのですが、配列に対してSystem.arraycopy
を行うとDeepコピーとなり、
コピー先の配列の要素を変更しても、コピー元の要素の値が変更されることはない
という事がテキストやwebページに記載されていました。

しかし、以下のコードではコピー元の配列の値が変更されてしまっています。
これは基本型が値のコピーを行うのに対し、オブジェクト型は参照値をコピーしているため変更されたという解釈でよろしいのでしょうか?
どうかご教授の程お願い申し上げます。

発生している問題・エラーメッセージ

array[1].num の値が20ではなく10になっている

エラーメッセージ

該当のソースコード

java

1public class Main { 2 public static void main(String[] args){ 3 Sample[] array = { 4 new Sample(10), 5 new Sample(20) 6 }; 7 Sample[] array2 = new Sample[2]; 8 System.arraycopy(array,0,array2,0,array.length); 9 array2[1].num = 10; 10 System.out.println(array[1].num); // 20ではなく10 11 System.out.println(array2[1].num); // 10 12 } 13} 14 15class Sample{ 16 int num; 17 Sample(int num){ 18 this.num = num; 19 } 20}

試したこと

public class Main {
. public static void main(String[] args){
. int[] array = {
. 10,
. 20
. };
. int[] array2 = new int [2];
. System.arraycopy(array,0,array2,0,array.length);
. array2[1] = 10;
. System.out.println(array[1]); // これは20のままでした
. }
}

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

公式のJavadocには、特にディープコピーとは書かれていませんね。

https://docs.oracle.com/javase/jp/8/docs/api/java/lang/System.html#arraycopy-java.lang.Object-int-java.lang.Object-int-int-

配列のインスタンスに格納されているSampleインスタンスへの参照もそのままコピーされるので、arrayが格納しているSampleインスタンスへの参照がそのままarray2へコピーされます。

投稿2018/08/16 05:23

A-pZ

総合スコア12011

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TK_0831

2018/08/16 19:32

ご回答いただきありがとうございます。 初学者向けとされるページを読んでおりましたので、公式のJavadocは確認しておりませんでした。誤解を与える表現をしてしまい申し訳ございません。(今後は公式のページにも目を通すように致します。) やはりSystem.arraycopyではSampleインスタンスへの参照もそのままコピーされるのですね。 勉強になりました。 回答してくださった皆様本当にありがとうございました。
guest

0

まとめ
newで格納場所を確保する
・参照型の場合はnew =で代入しても参照アドレスがコピーされるだけ
・参照型の場合はfor文などを使ってコピー


解決になるか分かりませんが自分なりにコピーするならこれが今のところ最適かなと思います。

java

1 public static void main(String[] args) { 2 Sample[] array1 = { 3 new Sample(10), 4 new Sample(20), 5 new Sample(30) 6 }; 7 8 Sample[] array2 = new Sample[array1.length]; 9 10 for(int i = 0; i < array1.length; i ++) { 11 array2[i] = new Sample(array1[i].num); 12 } 13 14 array2[1].num = 99; 15 16 System.out.println("array1[0] "+ array1[0].num); // 10 17 System.out.println("array1[1] "+ array1[1].num); // 20 元のまま 18 System.out.println("array1[2] "+ array1[2].num); // 30 19 20 System.out.println(); 21 22 System.out.println("array2[0] "+ array2[0].num); // 10 23 System.out.println("array2[1] "+ array2[1].num); // 99 ここだけ変更 24 System.out.println("array2[2] "+ array2[2].num); // 30 25 26 }

java

1public class Sample { 2 3 public int num; 4 5 Sample(int num) { 6 this.num = num; 7 } 8 9}

出力結果

array1[0] 10
array1[1] 20
array1[2] 30

array2[0] 10
array2[1] 99
array2[2] 30


【初心者が注意したい】Java配列コピーの方法まとめ

 参照型配列のコピー

使ったことのない気になった内容でしたので検索してみました。

分かりやすい記事があったのでリンク貼っておきますね。

記事の中でのサンプルコードではint[]でディープコピーの実演をされていました。

質問者さんのコードではclass Sampleをお使いのようですね。

まずはリンク先のようにint[]でお試ししてみてはどうでしょうか?

的外れな回答かもしれませんが見に来る方の参考にもなればと思いまして。


追記:
逆説的に実体がコピーされていないということはオブジェクト参照されている。
オブジェクト参照されているのでこの方法のままではコピー出来そうに無い。
別途イテレーションなどを使ってコピーし直す必要がありそうです。
イメージ説明
シャローコピーとディープコピー


↓リンク先の説明画像です
イメージ説明

投稿2018/08/16 06:29

編集2018/08/16 08:58
opyon

総合スコア1009

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

opyon

2018/08/16 07:03 編集

すでにint[]で試してたのですね失礼しました。 文法は間違っていなさそうなのでint[]とClassの違いにヒントがありそうですね。
LouiS0616

2018/08/16 06:52

細かい点ですが、JavaにはInt型はありません。intです。 頭文字が大文字だと参照型を連想しますので、この違いは割と気になります。
opyon

2018/08/16 07:04

ご指摘ありがとうございます修正しました。
opyon

2018/08/16 11:57

すみません。誤用している箇所があれば修正しますのでご指摘頂ければと思います。
TK_0831

2018/08/16 19:22

ご丁寧な回答ありがとうございます。リンク先の内容も大変わかりやすかったです。
guest

0

オブジェクトのクローン
こういった方法もあるようなのでご参考までに。
記事の中のサンプルコードそのままでは動かないので確認用に作ってみました。
※Class名は適当に変えて別々のファイルに保存してください。

java

1public class memo202 { 2 3 public static void main(String[] args) throws CloneNotSupportedException { 4 5 CloneTest c1 = new CloneTest(10); 6 CloneTest c2 = c1.clone(); 7 8 System.out.println("c1:" + c1.num); 9 System.out.println("c2:" + c2.num); 10 System.out.println(); 11 12 c2.num = 77; 13 14 System.out.println("c1:" + c1.num); 15 System.out.println("c2:" + c2.num); 16 } 17}

java

1public class CloneTest implements Cloneable { 2 3 public int num; 4 5 CloneTest(int num) { 6 this.num = num; 7 } 8 public CloneTest clone() throws CloneNotSupportedException { 9 return (CloneTest) super.clone(); 10 } 11}

出力結果

c1:10
c2:10

c1:10
c2:77

投稿2018/08/16 13:49

opyon

総合スコア1009

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

以下のコードではコピー元の配列の値が変更されてしまっています。

配列の値が変わっているのではなく、配列の中のオブジェクトの値が変わっているだけです。

arraycopyがディープコピーかどうかを調べたいなら、

java

1array2[1] = null;

などとするべきかと。

投稿2018/08/16 05:37

編集2018/08/16 05:37
fuzzball

総合スコア16731

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

momon-ga

2018/08/16 05:56

array2[1] = null; は、ディープコピーの確認にならないのでは? ディープコピーの検証は元のコードで良いと思います。
fuzzball

2018/08/16 06:05

配列のディープコピーは、配列そのものを複製するだけで、中の要素までは複製しないという認識なのですが、間違っているでしょうか?
momon-ga

2018/08/16 06:30 編集

認識か見解の相違のようです。 「配列そのものを複製するだけで、中の要素までは複製しない」を私は、シャローコピーとしています。 コピー先のオブジェクトを変更してもコピー元のオブジェクトが変更されないものをディープコピーとしています。 追記:今回のコピーの観点は、配列そのものでなく、配列の要素の話だと思っています。 なぜなら、array2はcloneでなくnewをしているので。
fuzzball

2018/08/16 06:37 編集

シャローコピーは配列そのものも複製しない、ようするに array2 = array です。 arraycopyのコピー対象は「配列」であって「配列の中身」ではないという認識です。 momon-gaさんは、例えばSampleの中に別のオブジェクトがあったとして(さらにその中にも別オブジェクトが‥)、再帰的にコピーしないとディープコピーと呼ばないということでしょうか?
momon-ga

2018/08/16 06:46

見解の相違なので、どちらが正しいとかは、あまり有意義な議論になりません。 私の場合、不変オブジェクトでないオブジェクトを含む場合、その値をcloneした別オブジェクトを作成しない場合、ディープコピーとしません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問