• ベストアンサー

コンストラクタで設定した値が表示されない

以下のプログラムを見ていただけたら分かるとおり、コンストラクタで設定した値が、配列だと表示されるのに、配列を使用していない変数だと表示されません。なせなのでしょうか? よろしくお願いします。 package test; public class test { public test(int[] idt, double ddt, String title) { title = "テスト"; ddt = 99.9; for(int i=0; i<idt.length; i++) { idt[i] = i; } } public static void main(String[] args) { int[] idt = {0, 0, 0}; double ddt=0.0; String title= ""; test t = new test(idt, ddt, title); for(int i=0; i<idt.length; i++) { System.out.println(idt[i]); } System.out.println(ddt + ", " + title); } }

質問者が選んだベストアンサー

  • ベストアンサー
noname#49664
noname#49664
回答No.2

これは要するに、引数として渡した変数の値をコンストラクタ内で変更している(つもり)なのになぜ変わらないか?ということでしょうか。 Javaでは、「プリミティブタイプは値渡し、オブジェクトは参照渡し」というのが基本です。intやdoubleなどは、値を保管する場所を確保し、それがそのまま変数に設定されます。これが引数などで渡されるときには、その値のコピーがメモリ内に作成され、それがメソッドの引数として渡されるわけです。つまり、元の変数とメソッドに渡された変数は別のものです。したがって、コンストラクタ側でどんなに操作しようと、元の変数の値は変わりません。別のものなのですから当然です。  これに対し、オブジェクトは参照(インスタンスがある場所を示す情報)渡しです。インスタンスを作成して変数に代入するとき、Javaではメモリ内にインスタンスを生成し、そのインスタンスがある場所を示す「参照」を値として変数に設定します。  メソッドなどで引数としてインスタンスを渡す場合には、この参照の値を新たにコピーした変数が作成され、これが割り当てられることになります。これにより、どちらも同じインスタンスを参照する値であるため、同じオブジェクトをそのまま引き継いで操作できるわけです。  したがって、渡されたインスタンスをそのまま利用して操作する場合、どちらも同じインスタンスを参照していますから片方で変更したものはもう片方でも反映されます。なにしろ同じものなんですから。配列を引渡してその中身を操作した場合、コンストラクタ側で操作するとmain側の変数にある配列も変わってしまうのはそれが理由です。  が、どちらの変数も同じインスタンスを参照してはいますが、あくまで「インスタンスがある場所を示す値が同じ」というだけなので、片方の変数に別のインスタンスの参照を入れてしまえば、両者は別のものを示すことになり、片方でインスタンスを変更してももう片方には反映されなくなります。  それが、Stringで値が反映されない理由です。コンストラクタ側の変数に新しいStringを代入した段階で、別のオブジェクトを参照するようになってしまっているのです。title = "テスト";というのは、いってみればtitle = new String("テスト");としているのと同じようなものです(正確には違いますが)。  ということは、メモリ内に新たに"テスト"というインスタンス(正確にはリテラル)を作成し、それを参照する値をtitleに代入する(つまり、この段階でmain側の変数とは別のオブジェクトを参照するようになっている)わけです。だから、コンストラクタ側が"テスト"になっているのに、main側は""のままなのです。 このあたりは、実際にいろいろと試してみるとなんとなくわかってきますよ。例えばですが。 String A = "Hello"; String B = A; A = "Bye"; これで変数Bの値はどうなるでしょうか? "Hello"になるはずですね。Aを"Bye"にしたからといって、Bも"Bye"にはなりません。なぜなら、A = "Bye"とした段階で、AにはBとは別のStringへの参照が設定されるために、両者は別々のStringを指し示すようになるからです。  では、今度はどうでしょう。 StringBuffer A = new StringBuffer("Hello"); StringBuffer B = A; A.delete(0,A.length()).append("Bye"); これで変数Bの値はどうなるでしょうか。実は、"Bye"になります。今回は、変数BにAと同じStringBufferを参照し、そのインスタンス自体を操作することで値を変更しています。新たな値を代入はしていません。したがって、最後まで変数AとBは同じインスタンスを参照することになり、Aを変更するとBも同じように変わるのです。  この両者の違いがわかるようになれば、疑問はとけると思いますよ。

kamakuragengorou
質問者

お礼

遅くなってしまい申し訳ありません。 丁寧かつ詳しく、このような長文で大変だったと思います。ご返答ありがとうございます。 >「プリミティブタイプは値渡し、オブジェクトは参照渡し」 これをJavaをやり始めた1年前に、本で読んだ記憶があります。しかしすっかり忘れていました。 おかげさまで思い出すことができ、その当時の謎も解き明かすことが出来ました。 ありがとうございました。

その他の回答 (3)

  • tom11
  • ベストアンサー率53% (134/251)
回答No.4

こんにちは、 書き換えてみました。 public class test { int [] idt; double ddt; String title; /** Creates a new instance of test */ public test(int []idt,double ddt,String title) { this.idt = new int[idt.length]; for(int i=0;i<idt.length;++i){ this.idt[i] = idt[i]; } this.ddt = ddt; this.title=title; } /** * @param args the command line arguments */ public static void main(String[] args) { int [] idt ={0,0,0}; test t = new test(idt,0.0,"テスト"); for(int i=0;i<t.idt.length;++i){ System.out.println(t.idt[i]); } System.out.println(t.ddt+","+t.title); //追加オブジェクト int [] idt1={1,2,3,4}; test t1 =new test(idt1,100.0,"テスト1"); for(int i=0;i<t1.idt.length;++i){ System.out.println(t1.idt[i]); } System.out.println(t1.ddt+","+t1.title); // TODO code application logic here } } こんな感じのほうが良いと思いますよ。

kamakuragengorou
質問者

お礼

遅くなってしまい申し訳ありません。ご返答ありがとうございます。 いつも丁寧なサンプルコードを示していただきありがとうございます。そういえばフィールドを用いて、「インスタンス.フィールド」で、そのクラスの変数をそのまま使うことが出来ましたよね。 ありがとうございました。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

コンストラクタでどうしてそのような副作用が必要なのかよくわかりませんが、 通常、参照型でないもの(double とかの基本データ型)を関数に渡す時には、関数にはそのコピーが渡されますので、 元の変数の内容は変更されません。

kamakuragengorou
質問者

お礼

遅くなってしまい申し訳ありません。簡潔で分かりやすいご返答ありがとうございます。 昔Javaを入門するときに読んでいたはずなのですが、すっかり忘れていました。このような基本的なことなのにすみません。 ありがとうございました。

noname#18558
noname#18558
回答No.1

配列やオブジェクトは参照渡しなので、メソッドやコンストラクタ内部で引数の内容を変更すると変わってしまいます。 一方、プリミティブ型は値渡しなので、変更されません。 参照渡しや値渡しはJavaに限らずプログラミングの基本なので覚えておいたほうがいいと思います。

kamakuragengorou
質問者

お礼

遅くなってしまい申し訳ありません。ご返答ありがとうございます。 そういえば昔Javaの本を読んでいたときに参照渡しや値渡しを見たことがありました。すっかり忘れてしまっていて、このような質問をしてしまいました。すみません。 ありがとうございました。