見出し画像

【Javaお勉強日記】インターフェイスについてまとめる

昨日のわたしへ。
継承については解ったけど、extendsじゃなくてimplementsのことあるよね
あれ何? の謎が解けます。
今日のわたしより。

インターフェイスとは何か

詳しい実装知らなくても、そこを通せば目的のオブジェクトを操作できる入口」の概念。

例えば、お店にあるクレジットカードの処理用の機械。裏側で何が起きてるかは解らないけど、どのカード会社のクレジットカードでも、なんならデビットカードでも、「中でどんな処理してるかは知らないけど、そこを通せばクレジットカード決済ができる」とみんな知っている。

で、将来新しいカード会社が誕生したとしても、今あるインターフェイスを通れるように、「カードはこのサイズで作ってね」「この位置にICカードを入れてね」「こういう信号送ったらこういう情報返してね」というお約束を守って貰えれば、新しい機械を作ったり、機械の大改造をしなくても、新しいカード会社のカードを受け入れることができる。

じゃあ、Javaのプログラム中ではどう活躍するのか

例えば、BookとCdとGameと、FoodとPcというオブジェクトを扱わなきゃいけないとする。

それぞれのオブジェクトには、「ログにオブジェクトの内容を端的に表示する」という機能が欲しいとする。

画像1

そのため、実行クラスに「受け取ったオブジェクトの、ログ表示クラスを呼ぶ」という処理を入れたい。そのために、その実行クラスを通る可能性のあるオブジェクトには全部、ログ表示メソッドを入れちゃおう

画像2

でも、こんどは「大丈夫?本当にそこに入ってくる全部のクラスにログ表示機能付いてる??」って心配になっちゃう。

それなら、「受け取れる型を制限しちゃって、絶対そのメソッドがある型だけを受け取れるようにしよう!」ってすればいいと思うじゃん。

でも、具体的に一つずつ「BookとCdとPcとFoodとGameしか通れないようにしました!!」ってすると、「今度Bagも必要になったから作ったよ!」ってなったときに、「Bagにはログ表示メソッドあるね、よし、じゃあリストに追加!」って一々手作業しないといけなくて、実用的じゃない…………

そこでインターフェイス型を作る

ココを通るものは、必ずこのメソッドを備えておくべし」という「お約束」を書いてあるのがインターフェイス型。

画像3

このインターフェイス型を、使いたいクラスに埋め込んでおく(implements)することで、「私このメソッド絶対持ってます!持ってなかったらコンパイルエラー出してます!だから通してください!」「よし、通れ!」という事が可能になる。

具体的にどういう仕組みで受け取っているかというと

// インターフェイス型を定義する。public,もしくはパッケージアクセスにする。
interface Display{
    // インターフェイス型の抽象クラスは全部 public abstract なので、一々書かない
    void display(); // 絶対displayメソッドが必要だよ!という約束
}

// Displayインターフェイスを埋め込んだBookクラスを作る
class Book implements Display{
   private String title;
   private String author;

   public Book(String title, String author){
       this.title = title;
       this.author = author;
   }
   // displayメソッドをオーバーライドする
   @Override
   public void display() {
       System.out.println(this.title + "/" + this.author);
   }
   
}

// 実行クラス
public class InterfaseTest {

   public static void main(String[] args) {
       // Book型のインスタンスだが、Display型を埋め込んであるので実はDisplay型でもある
       Book book1 = new Book("本のタイトル","著者名");
       displayTitle(book1);
   }
   
   // Display型で受け取るので、Displayインターフェイスで定義してある範囲だけ使える
   public static void displayTitle(Display item){
       item.display();
   }
}
・まずDisplayというインターフェイスを作る
・Displayインターフェイスを埋め込んだBookクラスを作る
・実行クラス内で、Bookクラスのインスタンスを作る。このとき、Book型で作るが、インターフェイスを埋め込んであるクラスのインスタンスは、同時にインスタンス型も持つので、Display型でもある。
・汎用メソッドは、インターフェイス型で引数を受け取る。

こうしておくと、後々Cdクラスを作った時にもDisplay型を実装しておくことで、実行クラスを書き換えなくてもCdクラスが使えるようになる。

その際、うっかりdisplay()のオーバーライドを忘れた場合は、コンパイルエラーになるので、「うっかり忘れる」がなくなる。

インターフェイスの継承

インターフェイスは継承できる。

インターフェイス内には、「このメソッドを用意するように」というお約束しか書いていないので、あんまり深いこと考えず、多重継承とかしてもいい。

interface A extends B,C {}

という具合に書く。

この場合、インターフェイスAを実装したクラスは、A,B,C全てのインターフェイスに書かれているメソッドを全部オーバーライドしないといけない。

また、クラスに実装したインターフェイスは、サブクラスに引き継がれる。

スーパークラスAでインタフェースを実装し、メソッドaをオーバーライド
サブクラスBでメソッドaをさらにオーバーライド

という使い方も可能。

参考

「インターフェイスとは何か」については下記の記事が大変わかりやすかったです。

インターフェースとは?~継承とは役割が違う~|オブジェクト指向プログラミング(OOP)をおさらいしよう(3) - GiXo Ltd.

「「絶対必要なメソッド」なら継承で……いいのでは……?」と思ってしまって、しっくりこなくてうーんうーん、って思っていたのですが、こちらの記事で納得いきました。インターフェイスとは「お約束」だというのがポイントになりそう。

この記事が気に入ったらサポートをしてみませんか?