人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

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のメソッドも、変数も知っているはずなので。

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

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

●質問者: どらすけ
●カテゴリ:コンピュータ
✍キーワード: Class Java sub Super X void
○ 状態 :終了
└ 回答数 : 4/4件

▽最新の回答へ

1 ● yusukey
●20ポイント

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

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

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

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

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

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

なので代入できません。

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

http://www.sun.com/

◎質問者からの返答

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

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

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

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


2 ● b-wind
●15ポイント

型も引き継げる

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

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

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

◎質問者からの返答

うっ…お恥ずかしい。

混同していました。

ありがとうございます。


3 ● t_shiono
●30ポイント

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

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


仮定:

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

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

◎質問者からの返答

ありがとうございます!

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


4 ● quintia
●30ポイント

「知っている」というメタファをクラスやインスタンスに使うと妙な感じになります(少なくとも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

◎質問者からの返答

ありがとうございます。

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

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ