CodeGym /Java Blog /ランダム /Java にインターフェイスが必要な理由
John Squirrels
レベル 41
San Francisco

Java にインターフェイスが必要な理由

ランダム グループに公開済み
やあ!今日は、Java の重要な概念であるインターフェイスについて説明します。この言葉はおそらくあなたもよく知っているでしょう。たとえば、ほとんどのコンピュータ プログラムやゲームにはインターフェイスがあります。広い意味では、インターフェイスは、対話する 2 つの当事者を接続する一種の「リモコン」です。日常生活におけるインターフェースの簡単な例は、テレビのリモコンです。人間とテレビという 2 つのオブジェクトを接続し、音量を上げるまたは下げる、チャンネルを切り替える、テレビをオンまたはオフにするなどのさまざまなタスクを実行します。一方の当事者 (個人) が、第二の当事者にアクションを実行させるには、インターフェースにアクセスする (リモコンのボタンを押す) 必要があります。たとえば、テレビを次のチャンネルに変更します。さらに、ユーザーは テレビがどのように構成されているか、チャンネル変更プロセスが内部でどのように実装されているかを知る必要はありません。ユーザーがアクセスできるのはインターフェイスのみです。主な目的は、望ましい結果を得ることです。これはプログラミングや Java とどのような関係があるのでしょうか? すべて:) インターフェイスの作成は通常のクラスの作成と非常に似ていますが、代わりに単語を使用します。class では、インターフェースという単語を示します。最も単純な Java インターフェイスを見て、それがどのように機能するか、そしてなぜそれが必要なのかを見てみましょう。

public interface CanSwim {

     public void swim();
}
CanSwimインターフェース を作成しました。これはリモコンに少し似ていますが、「ボタン」が 1 つあります: swim()メソッドです。しかし、このリモコンはどうやって使うのでしょうか?これを行うには、メソッド、つまりリモコンのボタンを実装する必要があります。インターフェイスを使用するには、プログラム内の一部のクラスがそのメソッドを実装する必要があります。オブジェクトが「泳ぐことができる」クラスを作成してみましょう。たとえば、Duckクラスは次の条件に適合します。

public class Duck implements CanSwim {

    public void swim() {
        System.out.println("Duck, swim!");
    }

    public static void main(String[] args) {

        Duck duck = new Duck();
        duck.swim();
    }
}
「ここで何がわかるでしょうか? Duckクラスは、 implementsキーワードによってCanSwimインターフェイスに「関連付けられています」。継承を通じて 2 つのクラスを関連付けるのに同様のメカニズムを使用したことを思い出していただけるかもしれませんが、その場合は extends という単語を使用しました。完全に明確に説明すると、「パブリック クラス Duck は CanSwim を実装します」を文字通りに翻訳できます: 「パブリックDuckクラスはCanSwimインターフェイスを実装します。」これは、インターフェイスに関連付けられたクラスがそのすべてのメソッドを実装する必要があることを意味します。注意: 私たちのクラスは、次のようになります。インターフェイスにはメソッドがあり、それにはいくつかのロジックが含まれています。これは必須の要件です。DuckCanSwimswim()public class Duck implements CanSwimswim()クラス内にメソッドを作成しないとDuck、コンパイラは次のエラーを表示します。「Duck は抽象ではないため、CanSwim の抽象メソッド swim() をオーバーライドしません。なぜですか?」なぜこのようなことが起こるのでしょうか? テレビの例を使ってエラーを説明すると、チャンネルを変更できない「チャンネル変更」ボタンが付いたテレビのリモコンを誰かに渡すようなものです。ボタンを好きなだけ押すこともできますが、機能しません。リモコンはそれ自体でチャンネルを変更しません。テレビに信号を送信するだけで、チャンネル変更の複雑なプロセスが実行されます。アヒルも同様です。インターフェイスを使用して呼び出すことができるように、アヒルは泳ぎ方を知っている必要がありますCanSwim。方法がわからない場合は、CanSwimインターフェイスは、人とプログラムという 2 つの関係者を結びつけるものではありません。その人は、プログラム内で泳ぐswim()ためのメソッドを使用することはできません。Duckこれで、インターフェイスの目的がより明確に理解できるようになりました。インターフェイスは、インターフェイスを実装するクラスが持つ必要がある動作を記述します。「動作」はメソッドの集合です。複数のメッセンジャーを作成したい場合、最も簡単な方法はインターフェイスを作成することですMessenger。すべてのメッセンジャーには何が必要ですか? 基本レベルでは、メッセージを送受信できる必要があります。

public interface Messenger{

     public void sendMessage();

     public void getMessage();
}
これで、対応するインターフェイスを実装するメッセンジャー クラスを簡単に作成できるようになりました。コンパイラ自体は、それらをクラスに実装することを「強制」します。電報:

public class Telegram implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a Telegram message!");
    }

     public void getMessage() {
         System.out.println("Receiving a Telegram message!");
     }
}
ワッツアップ:

public class WhatsApp implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a WhatsApp message!");
    }

     public void getMessage() {
         System.out.println("Reading a WhatsApp message!");
     }
}
バイバー:

public class Viber implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a Viber message!");
    }

     public void getMessage() {
         System.out.println("Receiving a Viber message!");
     }
}
これにはどのような利点がありますか? その中で最も重要なものは疎結合です。クライアントのデータを収集するプログラムを設計していると想像してください。このClientクラスには、クライアントがどの特定のメッセンジャーを使用しているかを示すフィールドが必ず必要です。インターフェースがないと、これは奇妙に見えます。

public class Client {

    private WhatsApp whatsApp;
    private Telegram telegram;
    private Viber viber;
}
3 つのフィールドを作成しましたが、クライアントが持つことができるメッセンジャーは 1 つだけです。どちらなのかは分かりません。したがって、クライアントと通信できるようにするために、クラスにあらゆる可能性を追加する必要があります。nullそれらのうちの 1 つまたは 2 つは常に であり、プログラムにはまったく不要であることがわかります。代わりに私たちのインターフェースを使用することをお勧めします。

public class Client {

    private Messenger messenger;
}
これは疎結合の例です。クラス内で特定のメッセンジャー クラスを指定する代わりにClient、クライアントにメッセンジャーがあることを示すだけです。どちらが正確に決定されるかは、プログラムの実行中に決定されます。しかし、なぜこれにインターフェースが必要なのでしょうか? なぜそれらが言語に追加されたのでしょうか? それは良い質問であり、正しい質問です。通常の継承を使用して同じ結果を達成することはできないでしょうか? クラスMessengerが親であり、 、ViberTelegramWhatsApp子です。確かにそれは可能です。しかし、問題が 1 つあります。すでにご存知のとおり、Java には多重継承がありません。ただし、複数のインターフェイスがサポートされています。クラスは必要な数のインターフェイスを実装できます。Smartphone次のクラスがあると想像してください。Appフィールドは、スマートフォンにインストールされているアプリを表します。

public class Smartphone {

    private App app;
}
もちろん、アプリとメッセンジャーは似ていますが、それでも別のものです。メッセンジャーにはモバイル バージョンとデスクトップ バージョンが存在しますが、App は特にモバイル アプリを表します。Telegramこれが問題です。継承を使用すると、クラスにオブジェクトを追加できなくなりますSmartphone。結局のところ、クラスはと!Telegramを同時に継承することはできません。そして、すでにそれを継承させてクラスに追加しました。ただし、クラスは両方のインターフェイスを簡単に実装できます。したがって、クラスにオブジェクトを として与えることができ、それをクラスに として与えることができます。その方法は次のとおりです。 AppMessengerMessengerClientTelegramClientTelegramMessengerSmartphoneApp

public class Telegram implements Application, Messenger {

    // ...methods
}

public class Client {

    private Messenger messenger;

    public Client() {
        this.messenger = new Telegram();
    }
}


public class Smartphone {

    private Application application;

    public Smartphone() {
        this.application = new Telegram();
    }
}
Telegramこれで、クラスを希望どおりに 使用できるようになりました。場所によっては、 として機能しますApp。他の場所では、 として機能しますMessenger。すでにお気づきかと思いますが、インターフェイス メソッドは常に「空」です。つまり、実装がありません。その理由は単純です。インターフェースは動作を記述しますが、それを実装していません。「CanSwimインターフェイスを実装するすべてのオブジェクトは泳ぐことができなければなりません」: インターフェイスが私たちに伝えるのはこれだけです。魚、アヒル、馬の具体的な泳ぎ方はFish、、、、DuckHorseインターフェイスではなくクラスです。チャンネルを変えることがテレビの仕事であるのと同じです。リモコンにはこのためのボタンが表示されるだけです。ただし、Java 8 では、デフォルトのメソッドという興味深い追加機能が追加されました。たとえば、インターフェイスには 10 個のメソッドがあります。そのうち 9 つは異なるクラスで異なる実装を持っていますが、1 つはすべて同じように実装されています。Java 8 より前の以前では、インターフェイス メソッドには実装がまったくなく、コンパイラはすぐにエラーを返しました。これで、次のようなことができるようになります。

public interface CanSwim {

   public default void swim() {
       System.out.println("Swim!");
   }

   public void eat();

   public void run();
}
キーワードを使用してdefault、デフォルトの実装を持つインターフェイス メソッドを作成しました。eat()他の 2 つのメソッドと、run()を実装するすべてのクラスに独自の実装を提供する必要がありますCanSwim。メソッドでこれを行う必要はありませんswim()。実装はすべてのクラスで同じになります。ちなみに、気付かなかったとしても、過去のタスクですでにインターフェイスに遭遇しています :) ここに鮮やかな例があります: あなたは、およびインターフェイスJava にインターフェースが必要な理由 - 2を操作しました。より正確には、、、、などの実装を操作しました。同じ図は、1 つのクラスが同時に複数のインターフェイスを実装する例を明確に示しています。たとえば、と を実装します。ListSetArrayListLinkedListHashSetLinkedListListDeque(両端キュー) インターフェイス。あなたはMapインターフェース、あるいはそのHashMap実装についてよく知っています。ちなみに、この図はインターフェイスが他のインターフェイスを継承できるという機能を示しています。インターフェイスSortedMapは を継承しますMapが、 もDeque継承しますQueue。これは、あるインターフェイスが別のインターフェイスの拡張バージョンであるインターフェイス間の関係を表示する場合に必要です。 インターフェースの例を考えてみましょうQueue。まだレビューしていませんQueues, しかし、これはかなり単純で、店舗の通常の行列や行列と同じように機能します。アイテムはキューの最後にのみ追加でき、最初からのみ取得できます。ある時点で、開発者は両端で項目を追加および取得するために、キューの拡張バージョンが必要になりました。そこで彼らはDeque、両端キューであるインターフェイスを作成しました。通常のキューのメソッドがすべて備わっています。結局のところ、これは両端キューの親ですが、新しいメソッドも追加されています。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION