アプリ版:「スタンプのみでお礼する」機能のリリースについて

下記のソースについて質問があります。

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)まで処理が行われるのは、何故かのかをご教授の程お願い致します。

A 回答 (10件)

>と言う認識であっているでしょうか。



それであってると思います。
    • good
    • 0

一言で言うと、


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()メソッドが呼ばれているわけです。
    • good
    • 0

>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/ …
    • good
    • 0

>焦点にしていることは、


>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);

ですから、後は戻り値をたどってください

この回答への補足

ご丁寧な説明を頂き、ありがとうございます。
おかげで、自分なりにわかるようになってきました。
で、確認したいことがありますので、下記にその内容を記載します

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() の値が出力される。

と言う認識であっているでしょうか。

宜しくお願い致します。

補足日時:2007/05/03 22:57
    • good
    • 0

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/ …

http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ …

http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ …

引数が null の場合は、"null" に等しい文字列。そうでない場合は、obj.toString() の値、、、が表示されると書いてあります。

参考URL:http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ …
    • good
    • 0

原因ですが、



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

と出力される背景へのイメージがつかみにくい状態です。

補足日時:2007/05/03 00:08
    • good
    • 0

>このコンストラクタの呼び出しは、オブジェクトの生成と初期化が


行なわれるだけで

そこまでの理解は正しいです。それしか行われません。
それを「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)の処理は何故行なわれているのかが理解できない状態です。

コンストラクタの呼び出しはオブジェクトの生成のみであり、
メソッドの呼び出しは行なわれないため、矛盾を感じてしまい
理解することに苦しんでおります。

補足日時:2007/05/03 00:12
    • good
    • 0

>(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())の呼び出し
には、関係ないと思ってしまいます。

まだ、理解度が足りなくて申し訳ございません。

補足日時:2007/05/02 22:58
    • good
    • 0

これでうまくいきました。


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)*/
}
}
    • good
    • 0

/* 当方,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/doc …
を参考にします
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/doc …

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/doc …

valueOf

public static String valueOf(Object obj)

Object 引数の文字列表現を返します。

パラメータ:
obj - Object
戻り値:
引数が null の場合は、「null」に等しい文字列。【そうでない場合は、obj.toString() の値】
関連項目:
Object.toString()


つーことで実行されてます

*/

}
}

この回答への補足

かなり詳しく回答いただきありがとうございます^^
しかし、どうもピンとこないです。
オブジェクトを作成するために、ただコンストラクタを
呼び出しているだけで、画面に出力されるのは

null

のみになると思われます。

>new Test()によりクラスのインスタンスが出来ます。
>これらクラスは全て確かObjectを継承するんじゃありませんでしたっけ?

そうでしたっけ.....自分でもわからないです。
かなり、謎の多が多い状態です、

補足日時:2007/05/02 22:54
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!