【Javaの勉強】参照型キャストの問題

参照型キャストは継承やインタフェースと絡んで込み入った話になるので、ややこしいです。

暗黙の型変換

最初「ん?」と思うのですが、宣言した変数の型とインスタンス化しているクラスが違う場合があります。それは、継承関係やインタフェースの実装関係がある場合となります。

たとえば、Schoolクラスを継承したStudentクラスを作ったとしましょう。

このような場合、親クラスを変数の型にして、子クラスでインスタンス化することが可能です。これを参照型の暗黙の型変換ということがあります。

【参照型暗黙の型変換 構文】

親クラス型 変数 = new 子クラス();

具体的にコードを示します。

10行目でSchool型でsch変数を宣言し、Studentクラスをインスタンス化して代入しています。メソッドの呼び出しはしていないので何も出力されませんが、コンパイルは可能です。

注意しないといけないのは、これの逆、子クラス型で宣言して、親クラス型でインスタンス化・代入は出来ないということです。

【NG構文】

子クラス型 変数 = new 親クラス();

メソッドの呼び出し

メソッドの呼び出しで注意したいことがあります。インスタンス化したのは子クラスのStudentクラスですが、参照できるのは親クラスで変数の型となっているSchool型だけです。図式化するとこんな感じですが、正直めっちゃ紛らわしいです。

つまり、次のようにStudentクラス独自のメソッドであるnameメソッドを呼び出そうとするとコンパイルエラーになります。

逆に、Schoolクラスのholidayメソッドは呼び出しができます。

実行結果休日

また、一番ややこしいのは親クラスのメソッドをオーバーライドしているパターンです。

実行結果Studentクラスの氏名

nameメソッドは親クラスであるSchoolクラスにもあるので、これは実行可能です。ただし、子クラスであるStudentクラスにオーバーライドされているため、参照自体は子クラスのnameメソッドです。

ちなみに、親クラスのnameメソッドを呼び出すにはどうしたらいいんだということですが、superキーワードを使って次のように書くと呼び出せます。また、子クラスのnameメソッドで残った処理は、親クラスが呼び出されたあとに呼び出されます。

実行結果Schoolクラスの氏名
Studentクラスの氏名

ちょっと脱線しましたが、重要な話なので書いておきました。

キャストを利用した型変換

子クラス独自のメソッドはキャストを利用した型変換ということをすることによって、呼び出しが可能です。具体的なコードで説明します。

実行結果氏名

まずもう一つ、別の変数sch2を宣言します。変数の型は今回参照したいStudent型にします。ここに変数schを代入するようにします。ただし、このまま「Student sch2 = sch」にするとコンパイルエラーになります。理由は親クラス型を子クラス型に代入しようとしているからです。

親子関係、順序が大事!

この場合、無理やりschをsch2に代入するときに使うのがキャストです。schの前に(Student)を付けると、student型に変換されます。

人間の世界では親が兄弟になるなんてことはまずありえないのですが、JavaではOKです。

こうして型変換したStudent型変数sch2を使ってnameメソッドを呼び出したのが例5です。

当然、Student型でStudentクラスをインスタンス化してもnameメソッドは呼び出せます…

インスタンス化・オブジェクトを理解している人からすれば、Student型でStudentクラスをインスタンス化すればいいんじゃない?と思いますが、たしかにその通りです。

実行結果氏名

見ての通り、同じ結果ですね。ではなんでキャストがあるのか・・・というのはまだ学習段階の自分はわかっていません(^^;

複雑なコードを書いたりすると使う場面がくるのですかね。その時を楽しみに、勉強を進めていきたいと思います。

↓よろしければクリックをお願いします
にほんブログ村 IT技術ブログ プログラム・プログラマーへ
にほんブログ村