class A {

int x = 10;
void hello () {
System.out.println("Hello A with " + x);
}
}
class B extends A {
int x = 20;
void hello () {
System.out.println("Hello B with " + x);
}
}
class Test {
public static void main (String args[]) {
A obj = new B();
obj.hello();
System.out.println("x = " + obj.x);
}
}
このプログラムを実行すると、
Hello B with 20
x = 10
となりますが、
Hello B with 20 は理解できます。
x = 10 となる理屈がわかりません。
このオブジェクト思考の理屈が理解できるURLはありませんか。

回答の条件
  • 1人3回まで
  • 13歳以上
  • 登録:2010/04/18 18:38:31
  • 終了:2010/04/20 12:33:31

ベストアンサー

id:quintia No.3

quintia回答回数560ベストアンサー獲得回数692010/04/19 14:05:35

ポイント40pt

"オーバーライドすることはできない"は、"エラーにする"のではなくて、"隠蔽してしまう"の意です。

サブクラスの中で、スーパークラスと同じ名前のフィールドを宣言すると、スーパークラスのフィールドは隠蔽されます。


質問のソースは、

class A {
  int x = 10;
  void hello () {
    System.out.println("Hello A with " + x);
  }
}

class B extends A {
  int x2 = 20; //衝突しない名前にする
  void hello () {
    System.out.println("Hello B with " + x2);
  }
}

class Test {
  public static void main (String args[]) {
    A obj = new B();
    obj.hello();
    System.out.println("x = " + obj.x);
  }
}

と書いたのと同じです。

こう書けば質問のソースでは、

  • mainの中でobj.xとした時にクラスAのフィールドにアクセスしていること
  • 変数宣言がAなので、ダウンキャストしないとBのフィールドにアクセスできないこと

が理解できるかと思います。


この仕様の意図は、スーパークラスの修正のしやすさからのものです。

class A {}

class B extends A {
  int x = 10;
  void hello () {
    System.out.println("Hello B with " + x);
  }
}

とあるとします。hello()メソッド中のxがBのフィールドを指すのは自明です。

このあと、

class A {
  float x = 0.0f;
  void hoge() {
    x = ...;
  }
}

class B extends A {
  int x = 10;
  void hello () {
    System.out.println("Hello B with " + x);
  }
}

と修正した時に、B中に書いたxがAのフィールドを(オーパーライドして)指してしまっては大変です。

ましてやこれらが、同じソースファイルでない、そもそもソースファイルがない、という状況だと面倒なことになります。


サブクラスでスーパークラスと同じ名前のフィールドを宣言する、あるいはメソッド内でクラスフィールドと同じ名前の変数を宣言する、などした時に後者が隠蔽される理由が分かるのではないでしょうか。


http://java.sun.com/docs/books/jls/second_edition/html/classes.d...

id:patacyan

今すぐには理解できないんですが、今後しっかり勉強させてもらいます。

みなさん、ありがとうございました。

2010/04/20 12:32:59

その他の回答(2件)

id:koriki-kozou No.1

koriki-kozou回答回数480ベストアンサー獲得回数792010/04/18 19:34:38

ポイント30pt

int x = 10;はスーパークラスのメンバ変数

どこからでも参照可能


int x = 20;はサブクラスのメンバ変数

定義したサブクラス以下でのみ参照可能

上位のメンバ変数にオーバーラップ可能


System.out.println("Hello B with " + x);からは同じクラス内でオーバーラップされた20のほうを参照

クラス外からはラップされたものは見えないでスーパークラスのメンバ変数だけが見える


http://www.atmarkit.co.jp/fjava/rensai2/javaent04/javaent04.html

id:patacyan

ありがとうございます。

もっと勉強させてもらいます。

2010/04/20 12:31:37
id:hnagoya No.2

hnagoya回答回数26ベストアンサー獲得回数32010/04/18 20:58:05

ポイント30pt

「オブジェクト思考の理屈」ではなく Java の仕様・実装がそうなっているだけのようですが、以下のURLがご質問に該当する内容のように思います。

Javaの“常識”、“非常識” - 第2回 言語仕様編

Q.05 サブクラスでスーパークラスのインスタンス・フィールドをオーバーライドしているのに、期待したとおりの結果が得られません……

A.05 サブクラスでオーバーライドできるのはメソッドのみで、スーパークラスのインスタンス・フィールドを「オーバーライド」することはできません

http://www.itarchitect.jp/technology_and_programming/-/27052-5.h...

id:patacyan

> Java の仕様・実装がそうなっているだけ

> スーパークラスのインスタンス・フィールドを「オーバーライド」することはできません

なるほど、そうだったんですね。

ありがとうございます。

2010/04/20 12:30:36
id:quintia No.3

quintia回答回数560ベストアンサー獲得回数692010/04/19 14:05:35ここでベストアンサー

ポイント40pt

"オーバーライドすることはできない"は、"エラーにする"のではなくて、"隠蔽してしまう"の意です。

サブクラスの中で、スーパークラスと同じ名前のフィールドを宣言すると、スーパークラスのフィールドは隠蔽されます。


質問のソースは、

class A {
  int x = 10;
  void hello () {
    System.out.println("Hello A with " + x);
  }
}

class B extends A {
  int x2 = 20; //衝突しない名前にする
  void hello () {
    System.out.println("Hello B with " + x2);
  }
}

class Test {
  public static void main (String args[]) {
    A obj = new B();
    obj.hello();
    System.out.println("x = " + obj.x);
  }
}

と書いたのと同じです。

こう書けば質問のソースでは、

  • mainの中でobj.xとした時にクラスAのフィールドにアクセスしていること
  • 変数宣言がAなので、ダウンキャストしないとBのフィールドにアクセスできないこと

が理解できるかと思います。


この仕様の意図は、スーパークラスの修正のしやすさからのものです。

class A {}

class B extends A {
  int x = 10;
  void hello () {
    System.out.println("Hello B with " + x);
  }
}

とあるとします。hello()メソッド中のxがBのフィールドを指すのは自明です。

このあと、

class A {
  float x = 0.0f;
  void hoge() {
    x = ...;
  }
}

class B extends A {
  int x = 10;
  void hello () {
    System.out.println("Hello B with " + x);
  }
}

と修正した時に、B中に書いたxがAのフィールドを(オーパーライドして)指してしまっては大変です。

ましてやこれらが、同じソースファイルでない、そもそもソースファイルがない、という状況だと面倒なことになります。


サブクラスでスーパークラスと同じ名前のフィールドを宣言する、あるいはメソッド内でクラスフィールドと同じ名前の変数を宣言する、などした時に後者が隠蔽される理由が分かるのではないでしょうか。


http://java.sun.com/docs/books/jls/second_edition/html/classes.d...

id:patacyan

今すぐには理解できないんですが、今後しっかり勉強させてもらいます。

みなさん、ありがとうございました。

2010/04/20 12:32:59

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません