• ベストアンサー

『sun教科書 javaプログラマ』で勉強している者です

javaの資格を取るべく独学中の者なのですが、回答を読んでも何故そうなるのか理解できない問題に出くわして困っています。ご教授いただければ助かりますm(__)m [問題3-15] 次のコードがあります。 public class CodeWalkTwo { int x = 3; static int y = 2; public static void main(String[] args){ int x = 10; int y = 10; CodeWalkTwo boardWalk = new CodeWalkTwo(); boardWalk.printIt(); boardWalk.printIt(y); } {x = x+1;} static{y += y;} void printIt(){ System.out.print(++x); } void printIt(int y){ System.out.print(" " + ++y); } } 実行結果は次のどれですか。 A. 5 11 B. 11 11 C. 5 5 D. 17行目でコンパイルエラーが発生する E. 5行目と6行目でコンパイルエラーが発生する 正解はA。その理由は2・3行目で宣言されるインスタンス変数およびstatic変数と、5・6行目で宣言されるローカル変数とは異なるスコープだからなのだそうですが、解説が短すぎてよく分かりません>< なぜ、片方はインスタンス変数でもう一方はローカル変数を実行しているのでしょう?

  • Java
  • 回答数4
  • ありがとう数1

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

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

実際の現場では、こういったようなコード(問題3-15)はあんまし好ましくないんですけどね。そもそも、一文字変数というのはループの中だけとか局所的、限定的に使われるべきであって、それこそ周りの開発者さんに忌み嫌われると思います。(私自身、そういう時代がありましたよ。今だからこそ、こういったような偉そうな口が叩けるんですけども。) まあ、ちょっとだけこの本の著者さんのフォローをするとすれば、実際にはこれと同じくらい、もしくは人によってはそれ以上とも言えるぐらい複雑な問題が出たりするんですよ。中には、全てのコードが表示されずに、「何行目から何行目まではこのようになっています。」みたいな感じで、かいつまんで出題されてたりしますからね。もちろん、それでも本当に理解できている人であれば、1コードずつ追っていくことができるわけでして。 >なぜ、片方はインスタンス変数でもう一方はローカル変数を実行しているのでしょう? 片方のインスタンス変数を実行しているprintIt()内では「this」が省略されていて、もう一方のローカル変数を実行しているprintIt(int y)内では自メソッドの引数が使われているからです。 実際には、以下のように変更してみるとよく分かることと思います。 // 18行目を以下のように改変。(3+1)+1=5で、結果は同じ。 System.out.print(++this.x); // 22行目を以下のように改変。(2+2)+1=5で、ローカル変数「int y = 10;」は使用されず。 System.out.print(" " + ++this.y); 厳密には、mainメソッド内で以下のようなコードも使用可能です。(コメント内は、いずれもインスタンス生成直後の所に追加した場合。) boardWalk.printIt(x); // 「int x = 10;」が使われる。 boardWalk.printIt(boardWalk.x); // 「int x = 3;」に、インスタンス初期化子で1を加算しインクリメントを1。 boardWalk.printIt(boardWalk.y); // 「static int y = 2;」に、静的初期化子で2を加算しインクリメントを1。 boardWalk.printIt(CodeWalkTwo.y); // 「boardWalk.y」が引数の場合と同じ。 // boardWalk.printIt(CodeWalkTwo.x); // 「int x = 3;」の先頭にstaticがないので、コンパイルエラー。 最後に、this.printIt()やthis.printIt(y)については、mainメソッド内で直接使用することはできません。(ヒントは、インスタンスメソッドです。)

JavaStuden
質問者

補足

変数名が全部一緒なんて、ほんと分かり難いですよね。たぶん著者はわざとしたんだと思いますけど。 >22行目を以下のように改変。(2+2)+1=5で、ローカル変数「int y = 10;」は使用されず。 System.out.print(" " + ++this.y); 本文のコードを上記のとおりに書き換えると実行結果が「5 5」になりました。なるほどvoid printIt()内では「this」が省略されていて、インスタンス変数が参照されるのですね! ところで、このthisはコンパイラが自動的に提供しているキーワードだと思うのですが、どういうときに提供されたりされなかったりするのでしょう?void printIt(int y)内では提供されていないようなので。 それと”もう一方のローカル変数を実行しているprintIt(int y)内では自メソッドの引数が使われているからです”の部分をもうすこし詳しく教えてもらえないでしょうか。static変数もローカル変数もint yであることに変わりないと思うのですが…。 他言語での経験もなくjavaで初めてプログラミングを学ぼうと志している身です。回答の理解がわるい点はご了承ください(>_<)

その他の回答 (3)

回答No.4

>引数なしのメソッドの場合、その中で使われる変数はコンパイラによりthisキーワードが供給されてインスタンス変数あるいはstatic変数を呼び出す。そしてパラメータ変数が指定されていれば、そのメソッドが定義されているのと同じブロック内(スコープ内)のローカル変数にアクセスして実行する。 >ということでしょうか? その通りです(但し、今回のように「変数が同じ名前」の時のみ)。 今使われている本の最後のページまで読破し終えてから、もう一度このスレを読み直してみて下さい。その時には、また違った視点から理解が深まっていることと思います。(逆に言えば、なぜ私がこのような回答が出来るのかというと、一通りSJC-Pの勉強をし終えているからです。単にそれだけですね。)

JavaStuden
質問者

お礼

SJC-P試験の経験でいらしたんですか!どおりで痒いところにまで手が届く丁寧な回答だったわけですね。 >使われている本の最後のページまで読破し終えてから、もう一度このスレを読み直してみて下さい。 そうしてみます。現在あと2章を残すのみのなったのですが、前の部分を忘却していないか心配です^_^;。 とびとびの返信でしたが最後までの回答ありがとうございました。お世話になりましたm(__)m

回答No.3

>ところで、このthisはコンパイラが自動的に提供しているキーワードだと思うのですが、どういうときに提供されたりされなかったりするのでしょう?void printIt(int y)内では提供されていないようなので。 thisキーワードは、基本的に省略可能となっています(入力してもしなくてもどっちでも同じ)。ただし、メソッド内などある特定のブロック{}内で同名の引数などと区別したい場合には、thisを使用します。これが#1さんがおっしゃっていた、 『インスタンス変数、static変数とローカル変数、パラメータ変数が同じ名前の場合、 ローカル変数、パラメータ変数が使われるという決まりがあります。』 の意味です。void printIt(int y)内でも一番外側で定義されているフィールドを強制的に使用したければ、thisを使ってパラメータ変数が使われないようにしないといけないということです。 >それと”もう一方のローカル変数を実行しているprintIt(int y)内では自メソッドの引数が使われているからです”の部分をもうすこし詳しく教えてもらえないでしょうか。static変数もローカル変数もint yであることに変わりないと思うのですが…。 同じ「int y」でも、それぞれのyのスコープが違います。基本的に、ある変数のスコープというのは、その変数が定義されているブロック({}で囲まれている部分)内でのみ有効です。 [問題3-15]のコードではなぜかコンストラクタがないため、以下のようなコードを作ってみました。 CodeWalkTwo(int y){ System.out.println("y=" + y + ",this.y =" + this.y); this.y=y; // 1.フィールドの初期化。 System.out.println("y=" + y + ",this.y =" + this.y); y=this.y; // 2.コンストラクタの引数値を無効化。(フィールドで上書き。) System.out.println("y=" + y + ",this.y =" + this.y); } mainメソッド内でのインスタンス生成時で、以下のように変更してから実行すると、次のような結果となります。 CodeWalkTwo boardWalk = new CodeWalkTwo(y); // コンストラクタの引数を指定。 [実行結果1→2] y=10,this.y =4 y=10,this.y =10 y=10,this.y =10 5 11 ちなみに、「this.y=y;」と「y=this.y;」の実行順序を逆にすると以下のような結果となります。 [実行結果2→1] y=10,this.y =4 y=4,this.y =4 y=4,this.y =4 5 11

JavaStuden
質問者

補足

たびたびの親切な回答ありがとうございますm(__)m。理解できているのか自信がないので確認させてください。 引数なしのメソッドの場合、その中で使われる変数はコンパイラによりthisキーワードが供給されてインスタンス変数あるいはstatic変数を呼び出す。そしてパラメータ変数が指定されていれば、そのメソッドが定義されているのと同じブロック内(スコープ内)のローカル変数にアクセスして実行する。 ということでしょうか?

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

非常にややこしいので、変数x、yの名前をちょっと変えると、 class CodeWalkTwo {  int instanceX = 3; //インスタンス変数  static int staticY = 2; //static変数  public static void main(String[] args){   int localX = 10; //ローカル変数   int localY = 10; //ローカル変数   CodeWalkTwo boardWalk = new CodeWalkTwo();   boardWalk.printIt();   boardWalk.printIt(localY); //(1)ローカル変数が使われる  }  {instanceX = instanceX+1;} //static修飾子  static{staticY += staticY;} //static修飾子(実はstaticYはここでしか使われていない)  void printIt(){   System.out.print(++instanceX); //インスタンス変数  }  void printIt(int parameterY){ //パラメータ変数   System.out.print(" " + ++parameterY); //(2)パラメータ変数が使われる  } } ポイントはコメントで示した(1)、(2)ですが、 インスタンス変数、static変数とローカル変数、パラメータ変数が同じ名前の場合、 ローカル変数、パラメータ変数が使われるという決まりがあります。 あとは、順にどの値が入ってるかを追いかけてみれば見えてくると思います。

関連するQ&A

  • javaのローカル変数について

    基本的なことの質問ですがよろしくお願いいたします。 下記の様なソースコードでint y ;はローカル変数にあたると思いますが 確かローカル変数は初期化されないとコンパイルエラーになるはずなのですが どうもコンパイルも実行もできます。 どうしてでしょうか? よろしくお願いいたします。 class Test1{ static int x = 0; } public class Test extends Test1{ public static void main(String args[]){ Test i = new Test(); int y ; y = ++x; System.out.println( y ) ; } }

    • ベストアンサー
    • Java
  • forループの中での初期化

    class Foo{   public static void main(String args[]){     int x=10;     for(int i=0;i<5;i++){       System.out.print(x+i);     }     System.out.print("\n"+i);   } } このプログラムはコンパイルエラーが出ます。 iがforループの中で宣言されていてその外では無効だからです。 そこで class Foo{   public static void main(String args[]){     int x=10;     int i;     for(i=0;i<5;i++){       System.out.print(x+i);     }     System.out.print("\n i="+i);   } } のようにしてみました。 i=5と出ました。 ふと、iは確かに宣言されているけど、初期化はforの中でしかされていないのになぜコンパイルエラーにならなかったんだろう??、と思ってしまいました。 おかしくないでしょうか?

    • ベストアンサー
    • Java
  • 継承とオーバーライド

    サブクラスのインスタンスを、スーパークラスの変数に代入するときの考え方が分かりません。下記のプログラムを実行すると x: 10 Sub という結果にります。 spで、message()を呼び出してるのだから、Superクラスのmessage()が処理されるのではないでしょうか? また、コメントアウトすると、コンパイルエラーになる理由もわかりません。 上記の答えのように、Subクラスのmessage()を参照できるのでしたら、printY()も参照できるんじゃないのかって思います。 基本的な質問かもしれませんが、よろしくお願いします。 class Super{ int x = 10; void printX(){ System.out.println("x:" + x); } void message(){ System.out.println("Super"); } } class Sub extends Super{ int y; void printY(){ System.out.println("Y:" +y ); } void message(){ System.out.println("Sub"); } } class ExtensSample01{ public static void main(String[] args){ Super sp = new Sub(); sp.printX(); // sp.printY(); sp. message(); } }

    • ベストアンサー
    • Java
  • コンパイルエラー

    以下のようなソースファイルをコンパイルしたらコンパイルに失敗してしまいました。エラーは『Cls1はabstractで宣言する必要があります。show(int)をCls1で定義しません』と出ます。これはどういうことでしょうか。 interface Int1 { int x=100; void Show(int y); } class Cls1 implements Int1 { public void show(int x) { System.out.println(x); } } class Test12 { public static void main(String args[]) { Cls1 c; c = new Cls1(); c.show(200); } }

    • ベストアンサー
    • Java
  • System.out.printがコンパイルできません。

    以前は普通にコンパイル→実行と出来ていたのに、なぜか出来なくなってしまいました。 class HelloWorld {   public static void main(String[] args) {     System.out.print("HelloWorld!!");   } } の様な簡単なプログラムもコンパイルできません。 [エラーメッセージ] HelloWorld.java:3: シンボルを見つけられません。 シンボル: 変数 out 場所 : System の クラス System.out.print("HelloWorld!!"); [出来ていた→出来なくなったの間にしたこと。]  .NET Framework 2.0のインストール  QT TabBar(http://members.at.infoseek.co.jp/Quizo/freeware/)  のインストール→アンインストール  ・skypeのインストール [自分なりに試したこと]  使っていたSDK5.0を再インストール(環境変数も打ち直しました。)  int x = 5;などSystem.out.printを含まない命令は実行できました。 もし原因等分かるようでしたら御回答宜しくお願いします。

    • ベストアンサー
    • Java
  • java初心者です。どうかよろしくお願いします。

    最初に最大公約数を求めるクラスを定義して、それを継承して最小公倍数を求めるプログラムを作ったのですがコンパイルはできても実行するとうまく作動しません。 理想の実行例は以下の通りです。 1st ? 12 2nd ? 8 Cookie=4 Late=24 ですが、1st? と 2nd? に数値を入力後に「Exception in thread "main" java.lang.ArithmeticException: / by zero」というエラーがどうしても出てきます。 なにが原因なのかさっぱり分からなくなり完全に詰まってしまいました・・・。 どなたか解る方がいらっしゃいましたら、どうか助けて下さい。 書いたソースコードは以下の通りです。 import java.io.*; class Cookie{ private int aa, bb; Cookie(int x, int y){ aa = x; bb = y; } public int cookie(){ int a = aa, b = bb; int r; while(b > 0){ r = a%b; a = b; b = r; } return a; } } class ChocoLate extends Cookie{ private int i,r; ChocoLate(int x, int y){ super(x,y); i = (x * y) /r; } public int late(){ return i; } } class sample{ public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.print("1st?"); String str1 = br.readLine(); System.out.print("2nd?"); String str2 = br.readLine(); int a = Integer.parseInt(str1); int b = Integer.parseInt(str2); ChocoLate lg = new ChocoLate(a,b); System.out.println("Cookie=" + lg.cookie()); System.out.println("Late=" + lg.late()); } }

    • ベストアンサー
    • Java
  • JAVA初心者です。

    以下の文法でコンパイルエラーが出ます。 添削をお願いします。 import java.util.Random; public class Test{ public static void main(String[] args){ int n; for (n = 0; n < 200; n++){ int i; for (i = 0; i < 38; i++) { Random rnd = new Random(); int ran = rnd.nextInt(10); System.out.print(ran); System.out.print(" "); for (t = 0; t < 200; t++) } System.out.println(); } } }

    • ベストアンサー
    • Java
  • クラス変数/メソッドとインスタンス変数/メソッドの見え方について

    Javaの言語仕様(?)についてお教え下さい。 参照変数の型がインスタンスのスーパークラスの型の時、クラス変数/メソッドとインスタンス変数/メソッドの見え方が納得いかずに困っています。 以下のような条件の時です。   ・クラスが2つあり、1つはもう1つのクラスを継承しています。     それぞれを「スーパー」「サブ」と以下で呼びます。   ・インスタンスは"サブ"の型です。   ・上記インスタンスへの参照変数は"スーパー"のクラスの型です。   ・"スーパー"、"サブ"ともに【同名】の「クラス」変数/メソッド、「インスタンス」変数/メソッドがあります。 この場合に、"サブ"のインスタンスを参照している"スーパー"の型の変数を介し、それらにアクセスしたらどれが見えるか?という疑問です。 実験結果では以下のようになりました。           [フィールド]  [メソッド]   [1.static ]  スーパーの   スーパーの   [2.非static]  スーパーの   サブの 納得いかないのは「2.非static」で「フィールド」が、「スーパーの」になるところです。 これも「サブの」になると思っていました。 なぜサブクラスのが見えないのでしょうか? 同名の変数なのでスーパークラスのはサブクラスので隠れされ、サブクラスのが見えると思っていたのですが。 参考書には以下のように書いてありました。   フィールドの場合、参照変数の型のものが見える。   メソッドの場合、インスタンスの型のものが見える。 私には不自然に感じられるのですが、「こういう仕様だから。」と納得するしか無いのでしょうか? 「なぜこうなるか」について説明がある文献、サイトなどありましたらお教えください。 参考までに以下が実験したサンプルコードと結果です。長くて申し訳ありません。 「サンプルコード」 public class Super { static int staticField = 10; int instanceField = 100; static void staticMethod() { System.out.println( "staticField = " + staticField ); } void instanceMethod() { System.out.println( "instanceField = " + instanceField ); } } public class Sub extends Super { static int staticField = 90; int instanceField = 900; static void staticMethod() { System.out.println( "staticField = " + staticField ); } void instanceMethod() { System.out.println( "instanceField = " + instanceField ); } } public class TestStatic { public static void main(String[] args) { // インスタンスはSub、参照変数もSub、という状態。 Sub sub = new Sub(); System.out.println( "実験1" ); System.out.println( "1.クラス変数      " + sub.staticField ); System.out.print( "2.クラスメソッド    " ); sub.staticMethod(); System.out.println( "3.インスタンス変数   " + sub.instanceField ); System.out.print( "4.インスタンスメソッド " ); sub.instanceMethod(); // インスタンスはSub、参照変数はSuper、という状態。 Super sup = new Sub(); System.out.println( "実験2" ); System.out.println( "5.クラス変数      " + sup.staticField ); System.out.print( "6.クラスメソッド    " ); sup.staticMethod(); System.out.println( "7.インスタンス変数   " + sup.instanceField ); System.out.print( "8.インスタンスメソッド " ); sup.instanceMethod(); } } 「結果」 実験1 1.クラス変数      90 2.クラスメソッド    staticField = 90 3.インスタンス変数   900 4.インスタンスメソッド instanceField = 900 実験2 5.クラス変数      10 6.クラスメソッド    staticField = 10 7.インスタンス変数   100 8.インスタンスメソッド instanceField = 900 納得が行かないのは7のところです。 以上よろしくお願いいたします。

    • ベストアンサー
    • Java
  • エラーの訂正でアドバイスください。

    javaプログラミング超初心者です import java.io.*; public class ex22b { public static void main(String[] arg) { System.out.print("x: "); int x = (new Integer (in.readLine())). intValue(); System.out.print("y: "); int y = (new Integer (in.readLine())). intValue(); int a; while (y > 0) { a = a + x; System.out.println("kekka = " + a); System.out.println("y = " + y); y = y - 1; } System.out.println("乗算結果は " + a); } } というソースを書いたら、コンパイルの際に シンボルを見つけられません シンボル:変数 in 場所  :ex22bのクラス int x = (new Integer (in.readLine())). intValue();            ^ int y = (new Integer (in.readLine())). intValue();            ^ というエラーが出ました。 どこをどう直したらいいのでしょうか。

    • ベストアンサー
    • Java
  • java初心者です。

    java初心者です。 イクリプスを使って、以下文のようなプログラムを実行しようとしたのですが、何度も「エディターにはメイン型が含まれていません」という画面が出てきて実行してくれません。 分かりやすい解決策をお待ちしています。よろしくおねがいします。 1class Sample1 2{ 3public static void main(String args[]) 4{ 5int num1=2; 6int num2=3; 7int sum =num1+num2 8 9System.out.prtintln("変数num1の値は"+num1+"です。"); 10System.out.prtintln("変数num2の値は"+num2+"です。"); 11System.out.prtintln("num1+num2の値は"+sum+"です。"); 12 13num1= num1+1; 14 15System.out.prtintln("変数num1の値に1をたすと"+num1+"です。"); 16} 17} 以上