- PR -

親クラスと子クラス間の配列について

1
投稿者投稿内容
wl
会議室デビュー日: 2004/09/19
投稿数: 3
投稿日時: 2004-10-10 15:36
皆さん始めまして、Java初心者のwlです。

親クラスと子クラス間の配列について皆さんにお聞きしたいのですが、
以下のクラスがあるときに、
class Super{}
class Sub extends Super {}
public class Sample {
public static void main(String[] args) {
Super[] sps = {new Sub(), new Sub()};
Sub[] sbs = (Sub[])sps;
}
何故『Sub[] sbs = (Sub[])sps;』ではコンパイルエラーにはならないが、
実行エラーになるのでしょうか?
Super[]とSub[]は何らかの形で関係を持っていますか?
ご存知の方是非教えてください。
宜しくお願いします。
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2004-10-10 15:54
wlさん、こんにちは。

Superと Subは super/subの関係であったとしても、
それらの配列 Super[]と Sub[]は各々別物で super/subの関係にありません。
配列はそれ自体がクラスであることを思い出してください。

(追加)
それと、
コード:
 Super[] sps = {new Sub(), new Sub()};


って
コード:
 Super[] sps = new Super[] {new Sub(), new Sub()};


としなくてもよかったでした?

[ メッセージ編集済み 編集者: Kissinger 編集日時 2004-10-10 15:57 ]
wl
会議室デビュー日: 2004/09/19
投稿数: 3
投稿日時: 2004-10-10 16:56
Kissingerさん、こんにちは。
返事していただき、どうもありがとう御座いました。


>Superと Subは super/subの関係であったとしても、
>それらの配列 Super[]と Sub[]は各々別物で super/subの関係にありません。
>配列はそれ自体がクラスであることを思い出してください。
⇒ご指摘の通りだと思います。
 しかし、自分が理解できないところは、もし関係がない場合
 何故コンパイルエラーにはならないというところです。
 一般的に継承関係のないクラス同士をキャストしようとすると
 コンパイルエラーになりますが、述べた例では、コンパイルエラーではなく
 実行時にエラーになります。


>Super[] sps = new Super[] {new Sub(), new Sub()};
>としなくてもよかったでした?
⇒しなくてもよいと思いますが、間違えっていたらご指摘願います。
 宜しくお願いします。
Gio
ぬし
会議室デビュー日: 2003/11/28
投稿数: 350
お住まい・勤務地: 都内から横浜の間に少量発生中
投稿日時: 2004-10-10 23:12
コンパイルエラーにならない理由ですが、それは java.lang.ClassCastException が非検査例外だからです。

詳しいことは言語仕様を参照していただきたいのですが、Super[] から Sub[] への変換は、要素型である Super から Sub への変換が参照型の縮小変換であるので、同様に参照型縮小変換になります。
この変換は実行時に検査されて、変換不可能な場合には ClassCastException が発生します。

コンパイルエラーになるケースですが、これは次のように一方が他方のサブクラスであるという関係にない場合に発生します。

コード:
class A{}
class B{}
...
A a = new A();
B b = (B) a; // A と B が継承関係にない(禁止される変換)のでコンパイルエラー

Object o = new A();
B b = (B) o;
// Object (o の変数としての型)から B への変換は縮小変換なので、
// コンパイル時ではなく実行時に検査される。
// 結果として o のオブジェクトとしての型 A から B へは変換不可能であるためClassCastException。



かなり端折って書くと、変数としての型が合っていない場合はコンパイル時、変数の型は合っているがオブジェクトの型が合わない場合は実行時に検査されるということです。
Gio
ぬし
会議室デビュー日: 2003/11/28
投稿数: 350
お住まい・勤務地: 都内から横浜の間に少量発生中
投稿日時: 2004-10-10 23:20
Kissinger さんへのフォローです。

配列宣言時に初期化もする場合は
コード:
Super[] sps = {new Sub(), new Sub()};


で大丈夫ですね。

宣言だけして後で設定する場合は、ご指摘の通り
コード:
Super[] sps;
...
sps = new Super[] {new Sub(), new Sub()};


と書く必要があります。
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2004-10-11 00:03
Gioさん、
初期化の件、ありがとうございました。
wl
会議室デビュー日: 2004/09/19
投稿数: 3
投稿日時: 2004-10-11 13:46
Gioさん、非常に丁寧な説明どうもありがとう御座います。

確認ですが、
instanceofでfalseになるケースが実行エラーになり、
instanceofでコンパイルエラーになるケースがコンパイルエラーになる
という認識で大丈夫ですか?


[ メッセージ編集済み 編集者: wl 編集日時 2004-10-11 13:53 ]
1

スキルアップ/キャリアアップ(JOB@IT)