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はありませんか。
"オーバーライドすることはできない"は、"エラーにする"のではなくて、"隠蔽してしまう"の意です。
サブクラスの中で、スーパークラスと同じ名前のフィールドを宣言すると、スーパークラスのフィールドは隠蔽されます。
質問のソースは、
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); } }
と書いたのと同じです。
こう書けば質問のソースでは、
が理解できるかと思います。
この仕様の意図は、スーパークラスの修正のしやすさからのものです。
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...
int x = 10;はスーパークラスのメンバ変数
どこからでも参照可能
int x = 20;はサブクラスのメンバ変数
定義したサブクラス以下でのみ参照可能
上位のメンバ変数にオーバーラップ可能
System.out.println("Hello B with " + x);からは同じクラス内でオーバーラップされた20のほうを参照
クラス外からはラップされたものは見えないでスーパークラスのメンバ変数だけが見える
http://www.atmarkit.co.jp/fjava/rensai2/javaent04/javaent04.html
ありがとうございます。
もっと勉強させてもらいます。
「オブジェクト思考の理屈」ではなく Java の仕様・実装がそうなっているだけのようですが、以下のURLがご質問に該当する内容のように思います。
Javaの“常識”、“非常識” - 第2回 言語仕様編
Q.05 サブクラスでスーパークラスのインスタンス・フィールドをオーバーライドしているのに、期待したとおりの結果が得られません……
A.05 サブクラスでオーバーライドできるのはメソッドのみで、スーパークラスのインスタンス・フィールドを「オーバーライド」することはできません
http://www.itarchitect.jp/technology_and_programming/-/27052-5.h...
> Java の仕様・実装がそうなっているだけ
> スーパークラスのインスタンス・フィールドを「オーバーライド」することはできません
なるほど、そうだったんですね。
ありがとうございます。
"オーバーライドすることはできない"は、"エラーにする"のではなくて、"隠蔽してしまう"の意です。
サブクラスの中で、スーパークラスと同じ名前のフィールドを宣言すると、スーパークラスのフィールドは隠蔽されます。
質問のソースは、
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); } }
と書いたのと同じです。
こう書けば質問のソースでは、
が理解できるかと思います。
この仕様の意図は、スーパークラスの修正のしやすさからのものです。
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...
今すぐには理解できないんですが、今後しっかり勉強させてもらいます。
みなさん、ありがとうございました。
今すぐには理解できないんですが、今後しっかり勉強させてもらいます。
みなさん、ありがとうございました。