
今回は…
というテーマでお送りします。

そして今度は、参照型の型変換ですね。
今回も、頑張ります。

今回も、楽しみです。よろしくお願いします。
【1】 参照型の型変換


学習しましたね。覚えていますか?
それに引き続いて、今度は…
です。
まず、イメージから見ていきましょう。
ある クラス ClassA があります。
ClassA の中で定義されているメソッドは
methodX() と methodY() です。

ClassA を継承したクラスClassB があります。
ClassAがスーパークラス
ClassBがサブクラスですね。

ClassBの中で追加で定義されているメソッドは
methodZ()です。

この ClassB をインスタンス化して 変数に代入します。

右辺の意味は、インスタンス化(実体として領域確保)
された型はClassBという事です。
左辺の意味は、ClassBという参照型で
変数 b が宣言されて…
右辺でインスタンス化された
先頭のアドレスが格納されるという事です。

右辺のインスタンスの型はClassB。
左辺の参照の型もClassBです。
この先頭アドレスが例えば100番地としましょう。
この b には インスタンス化された
先頭の番地が格納されます。
bの値は100番地です。

そして、ClassBを指し示すbがアクセスできる範囲は
ClassB 全体ということになります。

methodY();
methodZ();
…に、アクセスできます。

そして、参照型の型変換です。

このように記述すると
変数aに
変数bの値を代入することとなります。
値は変わらず100番地ですが…
参照の型はスーパークラスのClassAです。

このように、サブクラスの参照値を
スーパークラス型の変数に代入する事ができます。
これを
といいます。

変数aの参照の型はClassAです。
こうなると a でアクセスできる範囲は
ClassAの範囲となります。

にはアクセスできますが…
にはアクセスできない事となります。
そして、参照型の型変換をもうひとつ。
このように記述すると
変数b2に
変数aの値を代入することとなります。

値は変わらず100番地ですが
参照の型が変わっています。
参照の型はサブクラスのClassBです。

このように、スーパークラスの参照値(アップキャスト後)を
サブクラス型の変数に代入する事ができます。
これを
といいます。

サブクラスの中には、スーパークラスの部分を
全て含んでいるので…
アップキャストの場合には
自動的に(参照の)型変換が 行われます。

これに対して、ダウンキャストは
参照する範囲を 広げる形になりますので…
プログラマが明示的に キャスト演算子「()」を用いて
Javaに ダウンキャストして大丈夫な旨を 伝えます。

ここで、変数b2の参照の型はClassBですので。
アクセスできる範囲は、ClassB全体となります。

b2.methodY();
b2.methodZ();
の、3つのメソッドにアクセスできる事となりますね。
この部分、このイメージで押さえておきましょう。
ここまでをまとめると、こうなります。
✅ サブクラス型の変数をスーパークラス型の変数に代入できる。
✅ 型変換されるのは変数の型。つまり参照の型。
✅ アクセスできる範囲は、スーパークラス部分に限定される。
(参照の型により、アクセスできる範囲が決まる。)
(ダウンキャスト:明示的型変換)
✅ インスタンス(実体)サブクラス型の場合
スーパークラス型の変数をサブクラス型の変数に代入できる。
✅ キャスト演算子「()」を用いる。
✅ アクセスできる範囲は、サブクラス全体となる。
(参照の型により、アクセスできる範囲が決まる。)
先程のイメージと併せて、押さえておきましょうね。

意味の違いが、バッチリ分かりました。

変わるという事なんですね。
ガッテン、承知の助。
【2】 インスタンスの型

前のコーナーでお話した、型変換については
あくまで…
についての変換方法です。

この、参照の型によって
ということです。
そして…
ということを理解しておいてください。

ClassB から ClassA に型変換されても
範囲外が消されるということはありません。

ということ
押さえておきましょうね。
【3】 instanceof

Javaでは、継承関係にあるオブジェクトを操作する場合…
インスタンスの型(実体の型)が
違っている


場合が多くあります。
例えば、このような場合です。
変数 a についての
参照の型は ClassA ですが…

そのインスタンスの型は
実行した時の状況により、異なる場合があります。
(サブクラスの場合も考えられます。)

このような場合に、この後の処理の中で…
サブクラスの型にダウンキャストして
使いたい時もあります。
この時には、ダウンキャストする時点で…
インスタンスの型が 期待する型かどうか
調べてからキャストする 必要が出てきます。

その、調べる方法が
という構文で調べる方法です。

例えば
この場合、変数aの指し示す実体が
ClassBか そのサブクラスの時に…
この式自体が true になります。

そうでない場合には false です。
つまり、
です。
【4】 ダイナミックバインディング

ここまで…
アクセスできる範囲が決まる
…というお話をしてきましたが…
今度は、メソッド実行時を考えてみましょう。
ここで、1つ問題です。
前のコーナーの例で…
スーパークラス ClassA のメソッドのうち
methodY() について、サブクラス ClassB で
オーバーライドしている場合を考えましょう。

この場合には、サブクラス ClassB で
methodY() をオーバーライド(再定義)しています。
利用する側で、ClassB をインスタンス化して
ClassB型の 変数 b に代入します。

そして、ClassA にアップキャストします。

前のコーナーまでの話で…
ここで、アクセスできるのは
ClassAで定義されている範囲になりました。

ここからが、問題です…。
a.methodY();
このように、methodY() を呼び出した時に…
実行されるのは?
① スーパークラス ClassA で定義した methodY()
② サブクラス ClassB で再定義した methodY()
どちらでしょう?


ClassA の範囲だから…。
最初に ClassA で定義した methodY() と思います。


もしかして、引っ掛けで
ClassB で再定義したほうかな…?


これは、
が実行される事となります。

この場合、インスタンス(実体)の型はClassB。
そして、参照(変数)の型はClassA ですね。
このような場合…
実行するメソッドが 決定されます。

ここでは、実体が ClassB のインスタンス ですので
ClassB でオーバーライドした メソッドが 実行対象となります。
これを
といいます。

大切なところなので、もう一度…
✅ 実行する対象は、インスタンス(実体)の型で決まります。
✅ 実行時に、動的に決まるので ダイナミックバインディング
(動的バインディング)といいます。
ここも、このイメージで 捉えておきましょうね。
【まとめ】

スーパークラス型の変数に代入できる。
(アップキャスト)
✅ スーパークラス型の変数は
キャスト演算子を使って
サブクラス型にキャストする。
(ダウンキャスト)
✅ 参照の型により、アクセスできる
メンバの範囲が決まる。
✅ インスタンス(実体)の型は不変。
調べる方法。
変数名 instanceof 型名
参照(変数)の型で決まる。
✅ 実行する対象(メソッド)は
インスタンス(実体)の型で決まる。
✅ 実行時に、動的に対象がが決まるので
ダイナミックバインディング
(動的バインディング)という。
今回も、ご覧いただき、ありがとうございます。