抽象クラスとインターフェース

ライン公式アカウント
オンラインレッスンのお得なクーポン配信しています!
このチャプターの目次

抽象クラス

抽象クラスとは、クラスの継承関係の考え方をより抽象的にしたものです。継承関係をより抽象的に表現したクラスのことです。継承されることが前提で定義され、abstractキーワードを使います。
Animalクラスを例にしてみます。
たくさんの動物がいる中で、吠え方を1つ特定するようなことができません。そのため、宣言だけを記述します。メソッドの中身を書きようがないのです。
抽象メソッドには、abstractキーワードを使用します。
抽象クラスAnimalを継承したDogクラスは、メソッドをオーバーライドする必要があります。
Animalのような具体的な処理を表現できない抽象的なクラスを「抽象クラス」と言います。

インターフェース

インターフェースとは、「抽象クラスの概念を強くしてメソッドの実装すらできなくしたもの」です。抽象クラスAnimalのメソッドには中身を実装していませんが、抽象メソッド以外に、具体的な内容のあるメソッドを定義することも可能です。これを具象メソッドと言います。
例えば、歩くとか食べるとか寝るなどのメソッドです。
でも、インターフェースは具象メソッドを実装することができないのです。
💡
Java8からdefaultメソッドとstaticメソッドの実装が可能になりましたが、本講座では扱いません。
クラスの規格のみを定義したものです。classキーワードの代わりにinterfaceと記述します。継承の解説で使用していた有線のイヤホンと、AirPodsのようなワイヤレスイヤホンを例にしてみます。
イヤホンをインターフェースすると以下のようになります。
ワイヤレスイヤホン(Earbuds)は以下のようになります。
クラスの継承の際には、というキーワードを使いますが、インターフェースの場合はというキーワードを使います。メソッドはオーバーライドする必要があります。これを「インターフェースを実装する」と言います。
でも、この例はインターフェースとそれを実装したクラスにはあまりふさわしくありません。なぜならEarphoneクラスのメソッドとメソッドは処理の中身に相当する機能があり、規格にはならないからです。
なので、別の名前のAudioAccesoryというものにしてみました。
Earphonesクラスはインターフェースとしていましたが、AudioAccesoryを実装したクラスに変更しました。
EarbudsがするのもAudioAccesoryインターフェースです。AudioAccesory規格を実装しています。
新しいクラスが生まれるかもしれません。それは"Headphones"(ヘッドホン)という名前で、AudioAccessoryインターフェースを実装します。
機器にBluetoothで接続することもあるでしょう。そのような場合は、Headphonesクラスを継承したWirelessHeadphonesクラスを作って、connectメソッドをオーバーライドすると良いでしょう。

抽象クラスとインターフェースの違い

抽象クラスに相応しくないクラス

introduceというメソッドを持った、Personクラスがあるとしましょう。
メソッドは、自己紹介をするメソッドです。
また、Personクラスを継承したStudentクラスがあるとしましょう。
メソッドをオーバーライドしています。
Personクラスのメソッドは必ずオーバーライドされる前提なら、メソッドの中身が実装されている必要はありません。
でも、Personクラスをabstractにして抽象クラスにするのはふさわしくありません。
Personクラスは「はじめまして…」と自己紹介する具体的な処理があるからです。
では、抽象クラスにはどのような親子関係になるクラスがふさわしいのでしょうか?

抽象クラスに相応しいクラス

ポリモーフィズムの解説で例にした、メソッドを持つAnimalクラスとそれを継承したDogクラスとWolfクラスの場合、Dogは「ワンワン」、Wolfは「ワォーン」と吠えます。では、Animalはどのように吠えるのでしょうか?
DogとWolfのメソッドには具体的な処理をかけるのですが、動物全般を表すようなクラスAnimalのメソッドには具体的な処理が書けないのです。

抽象クラスの使い所

抽象クラスに相応しいクラスとは、「抽象的で概念を示したもの」です。
クラスを概念でグループ化したいような時」に使います。
💡
is a 関係
ここで少し「is a 関係」という言葉について触れておきたいと思います。継承の解説でよく登場する表現なのですが、「〜は〜の一種である」という意味になります。
  • DogはAnimalの一種である
  • WolfはAnimalの一種である
というような時に使います。継承関係にある親子クラスは「is a 関係にある」といいます。

インターフェースの使い所

インターフェースは、クラスとは全く違うものです。メソッドをオーバーライドしますが、クラスの継承とは違う意味を持ちます。それは、親の機能を引き継がないからです。
では、一体なんなのでしょうか?
  • クラスの規格
  • 雛形
  • テンプレート
  • ルールブック
などとよく例えられます。つまり「is a 関係にない」ということです。
Javaでは、クラスの多重継承ができません。多重継承とは、複数の親クラスから子クラスを作ることを指します。しかし、Javaではこれができません。それでも、何らかの理由で多重継承をしたい時があります。
例えば、ポリライン(線)、三角形、円といったクラスがあるとしましょう。いずれも、描くというメソッドを持っています。
シェイプ、図という抽象クラスを継承するのがふさわしいでしょう。
ここに、ポリゴン(多角形)というクラスが登場するとします。三角形、円、ポリゴンクラスは線が閉じられているので、面積を求めることができます。というメソッドを持っています。
閉じられたシェイプインターフェースを実装しているのがふさわしいでしょう。
  • ポリライン(線)クラス
    • 1つのクラスを継承
  • 三角形クラスと円クラス
    • 1つのクラスを継承
    • 1つのインターフェースを実装
  • 多角形クラス
    • 1つのインターフェースを実装
ということになります。
インターフェースは、継承関係にないクラスを束ねたい(分類したい)時に使います!

インターフェイスについての補足

💡
筆者の経験談
初学者にとって、インターフェースは解説を聞いてもイメージが湧かない概念トップ1と言っても過言ではないほど難しい概念の1つです。プログラミングを始めて理解するまでに時間がかかる概念ですが、実際に使ってみると非常に便利な機能だと実感します。
これは20年以上前の話です。当時、私はWindowsで動作する医療系ソフトウェアの開発に携わっていました。
  • 描く
  • 消す
  • 拡大する
  • 縮小する
などのレントゲン写真をお絵描きができるソフトウェアでした。これらの操作には元に戻す(undo)/やり直し(redo)機能があり、それらを実行するためのインターフェースが定義されていました。
※ 〇〇Commandの〇〇の部分には描く、消す、拡大、縮小・・・に該当する名前が入ります。
描く、消す、拡大、縮小の操作はすべてICommandインターフェースを実装したクラスとして作成されていました。undoボタンが押されるとundo()メソッドを実行し、redoボタンが押されるとredo()メソッドを実行するという設計により、「元に戻す/やり直し」機能を非常にシンプルに実装することができました。
つまりインターフェースとは、「効率的に開発を進めるための仕組み」だと言えます。
複数のクラス間で共通の機能や振る舞いを定義する強力な方法であり、コードの再利用性と保守性を高めることができます。インターフェースを使うことで、異なるクラス階層のオブジェクトでも同じ操作を実行できるようになるわけです。