• ベストアンサー

コンストラクタの動作について

下記のソースについて質問があります。 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)まで処理が行われるのは、何故かのかをご教授の程お願い致します。

  • KGM
  • お礼率44% (66/148)
  • Java
  • 回答数10
  • ありがとう数3

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

  • ベストアンサー
回答No.8

>と言う認識であっているでしょうか。 それであってると思います。

その他の回答 (9)

  • neko_noko
  • ベストアンサー率45% (146/319)
回答No.10

一言で言うと、 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)
回答No.9

>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() の戻り値が出力されています

参考URL:
http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/lang/Object.html#toString()
  • hofchan
  • ベストアンサー率62% (17/27)
回答No.7

>焦点にしていることは、 >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); ですから、後は戻り値をたどってください

KGM
質問者

補足

ご丁寧な説明を頂き、ありがとうございます。 おかげで、自分なりにわかるようになってきました。 で、確認したいことがありますので、下記にその内容を記載します 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() の値が出力される。 と言う認識であっているでしょうか。 宜しくお願い致します。

  • hogejo
  • ベストアンサー率42% (11/26)
回答No.6

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() の値、、、が表示されると書いてあります。

参考URL:
http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/io/PrintWriter.html#println(java.lang.Object)
  • neko_noko
  • ベストアンサー率45% (146/319)
回答No.5

原因ですが、 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」が表示されるのです。

KGM
質問者

補足

書き込みありがとうございます。 説明で申し訳ございません。 msgがローカル変数であることや、nullになる原因については 判明しております。 焦点にしていることは、 System.out.println(new Test()); にて、コンストラクタだけ呼び出されているのに、 なぜ、public String toString()のメソッドが呼び出されて 画面に msg:null と出力される背景へのイメージがつかみにくい状態です。

回答No.4

>このコンストラクタの呼び出しは、オブジェクトの生成と初期化が 行なわれるだけで そこまでの理解は正しいです。それしか行われません。 それを「System.out.printlnしているからそうなる」んです。

KGM
質問者

補足

書き込みありがとうございます。 確認したいことがありますので、下記に記載いたします。 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)
回答No.3

>(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が正しいことがわかりますよ。

KGM
質問者

補足

自分の中では、画面に出力されるのは null のみになると思われます。 実際の出力は、 msg:null となり、3つの返信より、イメージをつかむことができないです。 このコンストラクタの呼び出しは、オブジェクトの生成と初期化が 行なわれるだけで、メソッド(public String toString())の呼び出し には、関係ないと思ってしまいます。 まだ、理解度が足りなくて申し訳ございません。

  • fortranxp
  • ベストアンサー率26% (181/684)
回答No.2

これでうまくいきました。 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)*/ } }

回答No.1

/* 当方,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() つーことで実行されてます */ } }

KGM
質問者

補足

かなり詳しく回答いただきありがとうございます^^ しかし、どうもピンとこないです。 オブジェクトを作成するために、ただコンストラクタを 呼び出しているだけで、画面に出力されるのは null のみになると思われます。 >new Test()によりクラスのインスタンスが出来ます。 >これらクラスは全て確かObjectを継承するんじゃありませんでしたっけ? そうでしたっけ.....自分でもわからないです。 かなり、謎の多が多い状態です、

関連するQ&A

  • SJC-Pの問題で分からない部分があります・・・

    非常に基本的な質問になってしまうのですがご容赦下さい。 現在、SJC-Pの問題集でコンストラクタに関する問題に引っかかっています。 ---- 1 public class Test { 2 private String msg; 3 public Test() { this ("Good Morning"); } 4 public Test(String msg) { msg = msg; } 5 public String toString(){ return ("msg : " + msg); } 6 7 public static void main(String args[]){ 8 System.out.println(new Test()); 9 } 10 } ---- の実行結果を答えよ、という問題で、行数を実行順に追った場合、 8→3→4→8 なのかな、と思い、実行結果は「Good Morning」として答え合わせをした所、結果は、「msg : null」でした。 解説文と前後関係を読むと、どうも 8→3→4→5→8 と途中で4行目の「msg = msg」をしている(インスタンス変数にメソッド引数を入れている)時に5行目のtoStringが動いているようなのですが、明示的には4行目にtoStringを呼ぶとは書かれていません。 これはこういったルールなのでしょうか。 どうしてこのようなルールが適用されるのでしょうか?  このルールの名称は何でしょうか?  初歩的な質問で大変恐縮ですが、どなたかご存知の方がいらっしゃいましたら教えて下さい。 宜しくお願い致します。

    • ベストアンサー
    • Java
  • JAVAコンストラクタについて

    JAVA のコンストラクタ定義の際に、下記のようにコンストラクタにvoidを付けた時と付けない時の処理結果が変わるのはなぜでしょうか。 (1) class O { protected int d; O(){ System.out.println("O = " + d); } } class Study_6_3main_void { public static void main(String args[]) { int i = 1; O OO = new O(); System.out.println("O = "); } } (2) class O { protected int d; void O(){ System.out.println("O = " + d); } } class Study_6_3main_void { public static void main(String args[]) { int i = 1; O OO = new O(); System.out.println("O = "); } } 実行結果 (1) O = 0 O = (2) O = 以上です。回答の程よろしくおねがいします。

    • ベストアンサー
    • Java
  • コンストラクタを使用したJavaのコンパイルがうまくいかない

    質問内容は、タイトル通りなのですが、 まず、元になるコンストラクタを使用したクラスのソースを以下に書きます。 class test1{ test1(){ System.out.println("コンストラクタ完了"); } } これをtest1.javaという形でコンパイルも終了し、 次に以下のようなソースを書いたstt1.javaを作りました。 class stt1{ public static void main(String[] args){ test1 t0; t0 = new test1(); } } これをコンパイルしようとしたのですが、 シンボルが見つけられないというエラーが出てしまいました。 シンボル:クラス test1 場所:stt1のクラス と出ていました。 現状として、解決方法をネットなどで調べたのですが問題がどこにあるのか分からない状態です。 どなたか詳しい方がいましたら教えていただけると幸いです。

  • Javaのコンストラクタについて教えてください

    Javaを勉強している初心者です。 次のようなプログラムがあります。 このプログラムでclass aおよびclass bのデフォルトコンストラクタ a() {}とb() {}をコーディングしていないとコンパイルエラーになります。 b() {}についてはclass bのパラメータのあるコンストラクタb(String s)がサブクラスclass cから明示的に呼ばれていないのでデフォルトコンストラクタb() {}をコーディングしないとエラーになる…と考えればよいのでしょうか。 それでは、a() {}はなぜ必要なのでしょうか。 どなたか教えてください。 class a { a() {} a(String s) { System.out.println("In a's constructor..."); System.out.println(s); } } class b extends a { b() {} b(String s) { super(s); System.out.println("In b's constructor..."); System.out.println(s); } } class c extends b { c(String s) { System.out.println("In c's constructor..."); System.out.println(s); } public void some() { System.out.println("something..."); } } public class appJ01 { public static void main(String args[]) { c obj = new c("Hello from Java!"); } } 

  • コンストラクタについて

    これも試験問題らしくて自分でやってみましたのであってるかどうか自信なくて どなたかみてみていただけたらと思います.よろしくお願いします。 下のソースファイルをコンストラクタを用いたものに修正しなさい class Sconst{ int x,y,z; void print(){ System.out.println(x); System.out.println(y); System.out.println(z); } } class ExConstTest{ public static void main (String[] args ){ Sconst sc=new Sconst(); sc.x=10; sc.y=30; sc.z=5; } } ------------------------------------------------------------- class Sconst{ int x,y,z; Sconst(){ x=10; y=30; z=5; } } class ExConstTest{ public static void main (String[] args ){ Sconst a1; Sconst a2; Sconst a3; a1=new Sconst(); a2=new Sconst(); a3=new Sconst(); System.out.println(a1.x); System.out.println(a2.x); System.out.println(a3.x); } }

    • ベストアンサー
    • Java
  • コンストラクタからメソッドを呼んではいけない?

    会社の先輩から、 「コンストラクタでメソッドを呼ぶな!」をいわれ 理由も聞かずにソースを修正したのですが、 なぜコンストラクタからメソッドを呼んではいけないのでしょうか? 例: public class MyClass{ public MyClass(){ test(); } private void test(){ System.out.println("test"); } } よろしくお願いします。

    • ベストアンサー
    • Java
  • コンストラクタで設定した値が表示されない

    以下のプログラムを見ていただけたら分かるとおり、コンストラクタで設定した値が、配列だと表示されるのに、配列を使用していない変数だと表示されません。なせなのでしょうか? よろしくお願いします。 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); } }

    • ベストアンサー
    • Java
  • コンパイルエラー(匿名クラス)

    下記ソースがコンパイルエラーを起こしてどうしたらよいか分かりません。 下記エラー参照 Main.java:2: 型の開始が不正です。 new String(){ ^ Main.java:6: <identifier> がありません。 };ん。 (下記ソース) class NormalClass{ new String(){ public String ToString(int n){ return n + ""; } }; } class Main{ public static void main(String args[]){ NormalClass test = new NormalClass(); System.out.println(test.ToString(10)); } }

    • ベストアンサー
    • Java
  • 静的メンバ、ネストクラス、enumのアクセス

    下記のコードを試した所、(1)(4)は無事動作しますが、 (2)と(3)はコンパイルエラーになってしまいます。 初め、静的メンバの場合はnullでも動作する事にすごい驚いたんですが、 どこまでなら問題なく動作するかのラインがわからなくてこまっています。もしよろしければアドバイスをよろしくお願いします。 class Test{ static String A="A"; static class B{ static String val = "B"; } enum C{A,B,C} } enum D{A,B,C} class Sta{ public static void main(String[] args){ Test y=null; D y2 = null; (1)System.out.println(y.A); (2)System.out.println(y.B.val); (3)System.out.println(y.C.A); (4)System.out.println(y2.C); }}

  • インスタンスの情報表示について

    Java初心者です。 例えば次のようなソースがあって、double型の変数numの情報を表示するためにtoStringをオーバーライドするとすると、どのようにすればStringを返せるのでしょうか。 public class Test { private double[] num; public Test(double a, double b, double c) { num = new double[3]; this.num[0]=a; this.num[1]=b; this.num[2]=c; } public toString() { // return "インスタンスは: "+ } public static void main(String args[]) { Test a = new Test(4.3, 5.6, 12.7); System.out.println(a.toString()); } }

専門家に質問してみよう