クラスの継承(2)

前回のまとめ

  • 継承するとメンバーを受け継ぐ
  • ただしメンバーのアクセス修飾子に注意
  • 継承の元となるクラスは「スーパークラス」、継承によって作られた新しいクラスは「サブクラス」
  • super: サブクラスからスーパークラスのメソッド(コンストラクタを含む)を呼び出すことができる
  • スーパークラスにあるメソッドをオーバーライド(上書き)することができる

サブクラスからスーパークラスへのキャスト

コード全体: Main1.java

サブクラスはスーパークラスのメンバーをすべて持っている。
よって、サブクラスのインスタンスはスーパークラスのインスタンスとみなしても(として扱っても)大丈夫だ。

実際に、次のようなコードが書ける。

これは、次のような状況だ。

サブクラスからスーパークラスへのキャスト

comicで使う場合はComicクラスのインスタンスとして扱うことができるが(当たり前)、comicAsBookで使う場合はBookクラスのメンバーしか使えない。つまり

は実行できるが、

はコンパイルエラーになる。

これができると何が嬉しいのだろうか?1つは「BookとComicを(Bookの情報だけになるが)同じように扱える」ということだ。前回は
BookとComicでそれぞれ配列を作ってデータを扱っていたが、まとめてBookの配列として扱うことができる。つまり、

とすることができる。ただし、bookList[1]は本来Comicだが、Book扱いになる。

Book扱いになる(つまりComicで追加されたメンバーは使えない)が、オーバーライドされたメソッドはどういう扱いになるのだろうか。
次の実行結果を確認しよう。

コメントにも書いてある通り、「どのクラスとして扱っているか」ではなく、「インスタンス化した時のクラス」の実装が使われる。

すべてのクラスはObjectクラスを継承している

コード全体: Magazine.java, Main2.java, Main3.java

雑誌を表すMagazineクラスを作ってみよう。

Objectクラス

オーバーライドする時にIDEを使うと、候補となるメソッドが表示されるが、Bookクラスで定義していないメソッドがあるのが確認できるはず。これはObjectクラスのメソッドである。
実は(Objectクラスを除く)すべてのクラスはObjectクラスを継承している。正確には「extends」で指定しない場合には、Objectクラスが自動的に継承される。
つまり「Objectを継承したBook」を継承しているのがMagazineという関係である。

すべてのクラスがObjectを継承しているのなら、Objectの配列は参照型ならすべて格納できる、ということになる。

toStringメソッド

ここでは、toStringメソッドをオーバーライドしてみよう。これにより、System.out.printlnの引数として指定した時に表示する文字列を指定することができる。

では、確認しよう。

instanceof演算子とスーパークラスからサブクラスへのキャスト

Object型のままだと、その中のインスタンスが何であってもできることが限られる。実際のインスタンスの型を判別してキャストしよう。型の判別にはinstanceof演算子(教科書P.126)を使う。instanceof演算子で、「指定した型にキャストできるか」を判断することができる。Bookクラスにキャストできる(つまりBookクラスかBookの子孫となるクラス)かどうか判別してCSVを出力してみよう。

equalsメソッド

参照型の比較には==が使えない場合が多い。比較が必要なクラスはObjectクラスのequalsメソッドをオーバーライドする、という慣例になっている(「慣例」と書いたが、多くのライブラリが前提としてるので、ほぼルールと言って良い)。
例えば、文字列の比較の例を見てみよう。

Magazineのequalsメソッドをオーバーライドしてみよう。

結果を確認しよう。