javaの継承についての質問です。


public class Super{
public void super(){
}
}

public class Sub extends Super{
public void sub(){
}
}

上記親クラスSuper、子クラスSubがあるとき、

①Super x = new Sub();//OK
②x.sub();//コンパイルエラー

③Sub x = new Super();//コンパイルエラー

上記②がコンパイルエラーになるのは、「Superはsubメソッドを知らないから」とありました。
となると、①がコンパイルエラーとなり、③がコンパイルに通るべきなのでは…と思うのです。
SubはSuperのメソッドも、変数も知っているはずなので。

基本的なことだと思うのですが、つまずいています。どのような考え方をすれば、①~③を理解できるのでしょうか。

ご回答、よろしくお願いします。

回答の条件
  • URL必須
  • 1人2回まで
  • 登録:
  • 終了:2007/06/22 00:01:45

回答4件)

id:yusukey No.1

回答回数73ベストアンサー獲得回数2

ポイント20pt

全ての Sub 型は Super 型である、といえます。

なので Sub のインスタンスを Super 型の変数に代入できます。

しかし、逆も然りではありません。

全ての Super型は Sub 型である、とは言えません。

Sub 型の変数には Sub 型のメソッドなどの特徴を実装したクラスのインスタンスが代入されるべきです。

Sub 型の変数に代入されているインスタンスは必ず Sub 型で宣言されているメソッドなどを呼び出せる必要がありますが、Super 型では Sub 型で宣言されているメソッドが実装されている保証がありませんね。

なので代入できません。

、という説明でわかりますでしょうか・・。

http://www.sun.com/

id:dorasuke

早速のご解答、ありがとうございます!

>全ての Sub 型は Super 型である、といえます。

とありますが、継承は親クラスのメソッド、変数だけでなく、型も引き継げるということなのでしょうか?

そう考えると、納得ができそうです…。

2007/06/17 23:05:30
id:b-wind No.2

回答回数3344ベストアンサー獲得回数440

ポイント15pt

型も引き継げる

Class と言うのは型そのものですよ。

型に対してメソッドが定義されているという風に、考える順番を逆にすれば分かりやすいかもしれません。

オブジェクト指向を正しく理解する:ITpro

id:dorasuke

うっ…お恥ずかしい。

混同していました。

ありがとうございます。

2007/06/20 02:39:48
id:t_shiono No.3

回答回数256ベストアンサー獲得回数22

ポイント30pt

実体や参照という概念の辺りで悩んでいるのかと思います。

書籍などで色々読んでいるかと思うので、動物などの例は見飽きたと思うので、ちょっと変わった見方かもしれませんが、こんな風に考えてはいかがでしょうか?


仮定:

クラスは箱の種別を表すもの。箱にはいくつかの穴が開いている。

Superは一つの穴Aが開いている。

SubはSuperを拡張して、AとBの二つの穴が開いている。

インスタンスはその箱にあう柔らかな突起が付いた中身。

メソッド呼び出しは穴から突起を押す動作。

※突起はや柔らかいので、穴がなくても箱に入れられるが、突起がないのに穴があると、合致しないのでその箱には入れられない。

Super x = new Sub()

を次のように読み替えてください。

Sub t = new Sub()
Super x = t;

tという箱に新しく作成した中身を入れる。

作成したものは、AとBにあうような突起が出ている。

xという箱にtに入っている中身を入れる。

Aに対応する突起はAの穴から出て、Bに対応する突起は穴がないのでつぶれている。

x.sub();

xという箱に入った状態では、Bに対応する突起は見えていないので、押せない。

Sub x = new Super();

Superの箱に合う中身を作成して、Subの箱に入れる。

Bの穴から出る突起がないために、当てはまらない。


いかがでしょうか?

少しはイメージしやすいのではないでしょうか?


Super x = new Sub();

とした時点で、xに入っているものはSubのインスタンスであるが、それを操作する人にとっては、Superの取り扱い方しかできないということになります。

ただ、この場合でも、

((Sub)x).sub();

とでもしてあげて、xはSuperのように見えるけど、Subのものだよと明記してあげることにより、正しく動作します。


http://q.hatena.ne.jp/answer

id:dorasuke

ありがとうございます!

身近な例でわかりやすいです。

2007/06/22 00:00:08
id:quintia No.4

回答回数562ベストアンサー獲得回数71

ポイント30pt

「知っている」というメタファをクラスやインスタンスに使うと妙な感じになります(少なくともJavaでは)。

特に、

SubはSuperのメソッドも、変数も知っているはずなので。

の「変数も」の部分が危ないです。

「クラス定義」が「変数」を知っているはずはないですし、new Sub() として作られる「インスタンス」が「自身か代入された変数」を知っているということもありません。


Super x; //※1
:
:
x = new Sub(); //※2
:
:
x.sub(); //※3

※1で、xという変数にSuperという型が指定されました。

これにより、「コンパイラ」はxという変数が指すインスタンスがSuperかそのサブクラスであるということを「知りました」。


※2 の右辺で、Subというクラスのインスタンスが生成されます。右辺の型はSubです。

Sub が Super のサブクラスであることを「コンパイラ」は「知っています」。

左辺の変数 x はSuper型ですが、Sub のインスタンスは Super として振る舞うことができるので、代入してもよいと「コンパイラ」は「判断します」。


※3 で、変数 x が指す何のインスタンスなのかを「コンパイラ」は「知りません」。しかしSuperであることは「知っています」(※1 から)。

そして Super に sub() というメソッドがないことを「コンパイラ」は「知っています」。

だからエラーになります。


そうはいっても、

Super x = new Sub();
x.sub();

こんなソースだと、x が指すのが Sub のインスタンスであることを「プログラマ」は「知っています」(繰り返しますがコンパイラは知りません)。

Super x = new Sub();
((Sub)x).sub();

で、x が Sub であることを「コンパイラ」に「知らせてやれば」sub()をコールできます。


「Sub のインスタンス」はsub()メソッドを持っていることを「知っている」から、呼び出せるはずだ、という考えは Java にはありません。

x.sub(); が「実行される」時点で、x が指すインスタンスが「判断する」という言語ではないんです。

「コンパイル時点」で変数 x の型を拠り所にして「判断する」言語です。


http://materia.jp/blog/20051104.html#p01

ダミーURL

id:dorasuke

ありがとうございます。

知った/知らないという考え方自体がまずかったですね。頭をリセットして…勉強し直します。

2007/06/22 00:00:05

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

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

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

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

回答リクエストを送信したユーザーはいません