- ベストアンサー
コンストラクタの動作について
下記のソースについて質問があります。 public class Test{ private String msg; public Test(){ this("Good morning"); } public Test(String msg){ msg = msg; } public String toString(){ /*(2)*/ return ("msg:" + msg); } public static void main(String args[]){ System.out.println(new Test()); /*(1)*/ } } このコードをコンパイルした出力結果は、 msg:null となるのですが、ここの仕組みがわかりません。 (1)でTestクラスのコンストラクタを呼び出し、msgに"Good morning"を設定し、 処理が終わると思うのですが、(2)の処理も行われてしまいます。 (1)では、Testのコンストラクタを設定しているだけに見えてしまうのですが、 (2)まで処理が行われるのは、何故かのかをご教授の程お願い致します。
- みんなの回答 (10)
- 専門家の回答
質問者が選んだベストアンサー
>と言う認識であっているでしょうか。 それであってると思います。
その他の回答 (9)
- neko_noko
- ベストアンサー率45% (146/319)
一言で言うと、 Testオブジェクトはnullではないですが、 Testオブジェクト内のメンバー変数msgがnullということです。 ここの違いははっきりと確認して下さい。 >ここでは、Objectクラスのobjというインスタンスを作っているため >nullではないため、obj.toString() の値が出力される。 >と言う認識であっているでしょうか。 この認識で問題ありません。 >戻り値:引数が null の場合は、"null" に等しい文字列。 >そうでない場合は、obj.toString() の値 System.out.println(new Test()); ここでnullかどうか見ている対象は、Testオブジェクトのことです。 Testオブジェクトはnewで生成されているので、nullではありません。 TestクラスのtoString()メソッドで、 return ("msg:" + msg); こういう記述があると思います。この処理の「"msg:" + msg」の部分に着目します。 これは、"msg:"という文字列と、msgというStringオブジェクトを連結しているわけですが、 実際にはこんな処理が動いています。 "msg:".toString() + msg.toString() ※「+」の処理が内部的にどうなっているかは、ここでは重要でないので省略 文字列連結は、データ型がObject型ならそのtoString()メソッドを返す、となっているためです。 ここで、ようやくmsgがnullということが発覚し、"null"という文字列を返しているのです。 文字列を操作すると、至る所でtoString()メソッドが呼ばれているわけです。
- hofchan
- ベストアンサー率62% (17/27)
>public static String valueOf(Object obj) >のメソッドを通ることになりますが、(1)で生成された >オブジェクト(Object obj)はnullにはならないですよね?? 解らないことを棚上げにしない姿勢はいいですが、null かどうかは 御自分で、以下の様なコードを書けばわかります public class Test{ private String msg; public Test(){ this("Good morning"); } public Test(String msg){ msg = msg; System.out.println("Hello"); //追記 } public String toString(){ System.out.println("hoge");//追記 return ("msg:" + msg); } public static void main(String args[]){ Object obj = new Test(); if(obj == null){//追記 System.out.println("Hello"); } else { System.out.println("World"); } } } この手法をプリントデバッグと言います、自分のコードがどこを 通っているのかが目で見てわかり、大きなコードや 深いネスト等で重宝します >nullではないため、obj.toString() の値が出力される。 >と言う認識であっているでしょうか。 正確には オーバーライド された toString() の戻り値が出力されています
- hofchan
- ベストアンサー率62% (17/27)
>焦点にしていることは、 >System.out.println(new Test()); >にて、コンストラクタだけ呼び出されているのに、 まず、ここがおかしいです public class Test{ private String msg; public Test(){ this("Good morning"); } public Test(String msg){ msg = msg; System.out.println("Hello"); //追記 } public String toString(){ return ("msg:" + msg); } public static void main(String args[]){ new Test(); } } コンストラクタだけを呼び出すとは、上記です 元のコードは System.out.println(Object obj); ですから、後は戻り値をたどってください
- hogejo
- ベストアンサー率42% (11/26)
System.out.println(new Test()); は、以下の処理と同じです。 Object obj = new Test(); System.out.println(obj); // objのtoString()が呼ばれて、msgnull と表示される。 new Test()でコンストラクタが呼び出されてますが、println()にわたっているのはTestインスタンスです。msgnullと表示されるのはprintlnメソッドにTestインスタンスを渡した結果です。 println(Object obj)メソッドの仕様を見ると、以下のようになってます。 http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/io/PrintWriter.html#println(java.lang.Object) ↓ http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/io/PrintWriter.html#print(java.lang.Object) ↓ http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/lang/String.html#valueOf(java.lang.Object) ↓ 引数が null の場合は、"null" に等しい文字列。そうでない場合は、obj.toString() の値、、、が表示されると書いてあります。
- neko_noko
- ベストアンサー率45% (146/319)
原因ですが、 public Test(String msg){ msg = msg; } ここを、 public Test(String msg){ this.msg = msg; } として下さい。これで大丈夫なはずです。 何でそうなるのか?についてですが、 msg = msg; ここの処理ですが、おそらく private String msg;で定義したmsg (ややこしいので、この変数を「メンバー変数msg」と呼びます)に、 public Test(String msg){の引数msg (こちらを「ローカル変数msg」と呼びます)に代入している、 と考えていませんか? メンバー変数とローカル変数が同じ名前(この場合「msg」)の場合、 いきなり、「msg」と指定されても、どちらの変数を使用していいかコンピュータには判別できません。 なので、この場合は原則として「ローカル変数とする」と決まっています。 (これはJavaの言語仕様で決まっていることです) じゃあ、メンバー変数msgの方を指定したい場合はどうするか? ですが、メンバー変数を表すようにthis.msg とすることでコンピュータが理解できるようになるのです。 ちなみに、これは変数名がカブっている部分だけ適用されるものです。なので public String toString(){ /*(2)*/ return ("msg:" + msg); } このメソッド内では、msgはカブることはないので、 あえて「return ("msg:" + this.msg);」としなくても問題ないのです。 (this.msgとしても問題ありません。) public Test(String msg){} このメソッド内ではmsgがカブってしまうので、使い分けが必要なのです。 以上のことより、 msg = msg; ここでは、ローカル変数msgに、ローカル変数msgを代入する? という処理になっており、 メンバー変数msgは、何もされていないのです。 なので、メンバー変数msgは、いつまでたってもnullのままなので、 return ("msg:" + msg); ここで、「null」が表示されるのです。
補足
書き込みありがとうございます。 説明で申し訳ございません。 msgがローカル変数であることや、nullになる原因については 判明しております。 焦点にしていることは、 System.out.println(new Test()); にて、コンストラクタだけ呼び出されているのに、 なぜ、public String toString()のメソッドが呼び出されて 画面に msg:null と出力される背景へのイメージがつかみにくい状態です。
- himajin100000
- ベストアンサー率54% (1660/3060)
>このコンストラクタの呼び出しは、オブジェクトの生成と初期化が 行なわれるだけで そこまでの理解は正しいです。それしか行われません。 それを「System.out.printlnしているからそうなる」んです。
補足
書き込みありがとうございます。 確認したいことがありますので、下記に記載いたします。 System.out.println(new Test()); ^^^^^^^^^^^^(1) (1)によって、コンストラクタ(オブジェクト生成)の呼び出される。 public Test(){ this("Good morning"); ^^^^(2) } (2)によって、同クラスの別なコンストラクタ(public Test(String msg))に 移る public Test(String msg){ ^^^^^^^^^^^(3) msg = msg; } (3)によって、msg("Good morning")がローカル変数msgに代入される。 ※クラス変数のprivate String msgはnull public String toString(){ /*(2)*/ return ("msg:" + msg); ^^^^^^^^^^^^^^^^^^^^^^(4) } (3)実行後、toStringメソッドが呼び出されて、 (4)の処理(「msg:null(private String msg)」が返される)が実施される。 System.out.println(new Test()); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^(5) (4)の処理が、画面に出力される。 (1)-(5)までの一連の流れにより、画面に msg:null が出力されます。 ただここで、 >このコンストラクタの呼び出しは、オブジェクトの生成と初期化が >行なわれるだけで >そこまでの理解は正しいです。それしか行われません。 この返答に矛盾があるように感じてしまいます。 今回のソースでは、コンストラクタ呼出し後 toStringメソッドが呼び出され、return ("msg:" + msg);が行なわれ、 画面に「msg:null」が出力されています。 つまり、(4)の処理は何故行なわれているのかが理解できない状態です。 コンストラクタの呼び出しはオブジェクトの生成のみであり、 メソッドの呼び出しは行なわれないため、矛盾を感じてしまい 理解することに苦しんでおります。
- i2719
- ベストアンサー率35% (11/31)
>(2)まで処理が行われるのは、何故かのかをご教授の程お願い致します。 public String toString(){ /*(2)*/ new Throwable().printStackTrace(); として実行すると java.lang.Throwable at Test.toString(Test.java:10) at java.lang.String.valueOf(String.java:2577) at java.io.PrintStream.print(PrintStream.java:616) at java.io.PrintStream.println(PrintStream.java:753) at Test.main(Test.java:14) msg:null ANo.1が正しいことがわかりますよ。
補足
自分の中では、画面に出力されるのは null のみになると思われます。 実際の出力は、 msg:null となり、3つの返信より、イメージをつかむことができないです。 このコンストラクタの呼び出しは、オブジェクトの生成と初期化が 行なわれるだけで、メソッド(public String toString())の呼び出し には、関係ないと思ってしまいます。 まだ、理解度が足りなくて申し訳ございません。
- fortranxp
- ベストアンサー率26% (181/684)
これでうまくいきました。 public class Test070502{ private String msg; public Test070502(){ this.msg="Good morning"; } public Test070502(String msg){ this.msg = msg; } public String toString(){ /*(2)*/ return ("msg:" + msg); } public static void main(String args[]){ System.out.println(new Test070502()); /*(1)*/ } }
- himajin100000
- ベストアンサー率54% (1660/3060)
/* 当方,Java初心者です。*/ public class Test{ private String msg; public Test(){ this("Good morning"); /* 実はこの書式をはじめて知った人間だったり(汗)*/ } /* クラスのメンバ変数msgなのかローカル変数msgなのか判別がつきにくいので 勝手に置き換えましたが, 意図してないものであればごめんなさい*/ public Test(String message){ msg = message; } public String toString(){ /*(2)*/ return ("msg:" + msg); } public static void main(String args[]){ System.out.println(new Test()); /*(1)*/ /* http://sdc.sun.co.jp/java/docs/j2se/1.5.0/ja/docs/ja/api/java/io/PrintStream.html#println() を参考にします new Test()によりクラスのインスタンスが出来ます。 これらクラスは全て確かObjectを継承するんじゃありませんでしたっけ? すると実行されるメソッドは ======= println public void println(Object x) Object を出力して、行を終了します。 このメソッドは、print(object) を呼び出してから println() を呼び出すのと同じように動作します。 パラメータ: x - 出力される Object 値 ======= です。 さらに読むとこう書かれています。 ======== http://sdc.sun.co.jp/java/docs/j2se/1.5.0/ja/docs/ja/api/java/io/PrintStream.html#print(java.lang.Object) print public void print(Object obj) オブジェクトを出力します。String.valueOf(Object) メソッドにより作成された文字列は プラットフォームのデフォルトの文字エンコーディングに従ってバイトに変換され、 このバイトが write(int) メソッドとまったく同じ方法で書き込まれます。 パラメータ: obj - 出力される Object 値 関連項目: Object.toString() ====== さらに調べるとString.valueOfを調べると ====== http://sdc.sun.co.jp/java/docs/j2se/1.5.0/ja/docs/ja/api/java/lang/String.html#valueOf(java.lang.Object) valueOf public static String valueOf(Object obj) Object 引数の文字列表現を返します。 パラメータ: obj - Object 戻り値: 引数が null の場合は、「null」に等しい文字列。【そうでない場合は、obj.toString() の値】 関連項目: Object.toString() つーことで実行されてます */ } }
補足
かなり詳しく回答いただきありがとうございます^^ しかし、どうもピンとこないです。 オブジェクトを作成するために、ただコンストラクタを 呼び出しているだけで、画面に出力されるのは null のみになると思われます。 >new Test()によりクラスのインスタンスが出来ます。 >これらクラスは全て確かObjectを継承するんじゃありませんでしたっけ? そうでしたっけ.....自分でもわからないです。 かなり、謎の多が多い状態です、
補足
ご丁寧な説明を頂き、ありがとうございます。 おかげで、自分なりにわかるようになってきました。 で、確認したいことがありますので、下記にその内容を記載します System.out.println(Object obj); ^^^^^^^^^^^(1) (1)の箇所で 1.オブジェクトの生成 2.出力処理 が行なわれます。 その際、 public static String valueOf(Object obj) のメソッドを通ることになりますが、(1)で生成された オブジェクト(Object obj)はnullにはならないですよね?? APIリファレンスに記載されているvalueOfの戻り値の説明で 戻り値:引数が null の場合は、"null" に等しい文字列。 そうでない場合は、obj.toString() の値 があります。 ここでは、Objectクラスのobjというインスタンスを作っているため nullではないため、obj.toString() の値が出力される。 と言う認識であっているでしょうか。 宜しくお願い致します。