1. 能力

インターフェイスの利点とそれをどこで使用するかをよりよく理解するには、より抽象的なことについて説明する必要があります。

通常、クラスは特定のオブジェクトをモデル化します。インターフェイスはオブジェクトというよりも、オブジェクトの能力や役割に対応します。

インターフェースの本質

たとえば、車、自転車、オートバイ、ホイールなどは、クラスとオブジェクトとして表現するのが最適です。しかし、「乗れる」、「人を運ぶことができる」、「立つことができる」といった彼らの能力は、インターフェースとして表現したほうがよいでしょう。ここではいくつかの例を示します。

コード 説明
interface CanMove
{
   void move(String newLocation);
}
移動能力に対応
interface Rideable
{
   void ride(Passenger passenger);
}
乗れる能力に対応
interface CanTransport
{
   void addStuff(Object stuff);
   Object removeStuff();
}
物品の輸送能力に対応
class Wheel implements CanMove
{
   ...
}
クラスは移動Wheelできる
class Car implements CanMove, Rideable, CanTransport
{
   ...
}
クラスは移動したり、乗ったり、物を運んだりCarできます
class Skateboard implements CanMove, Rideable
{
   ...
}
クラスは移動して乗ることSkateboardができます


2. 役割

インターフェイスはプログラマの作業を大幅に簡素化します。非常に多くの場合、プログラムには数千のオブジェクト、数百のクラスがありますが、インターフェイス、つまりロールはほんの数十個しかありません。ロールの数は少ないですが、それらを組み合わせる方法 (クラス) はたくさんあります。

重要なのは、他のすべてのクラスと対話するために各クラスでコードを記述する必要がないということです。必要なのは、それらのロール (インターフェイス) と対話することだけです。

あなたがペットのトレーナーであると想像してください。あなたが扱うペットはそれぞれ、いくつかの異なる能力を持つことができます。あなたは、どのペットが最も騒音を発することができるかについて、隣人と友好的な議論を始めます。問題を解決するには、「話す」ことができるすべてのペットを並べて、「話せ!」と命令するだけです。

彼らがどんな種類の動物であるか、彼らが他のどんな能力を持っているかは気にしません。たとえ三回転宙返りができたとしても。この特定の瞬間、あなたは彼らが大声で話す能力だけに興味があります。コードでは次のようになります。

コード 説明
interface CanSpeak
{
   void speak();
}
能力CanSpeak。このインターフェイスはコマンド to を理解しますspeak。これは、対応するメソッドがあることを意味します。
class Cat implements CanSpeak
{
   void speak()
   {
      println("MEOW");
   }
}

class Dog implements CanSpeak
{
   void speak()
   {
      println("WOOF");
   }
}

class Fish
{
   ...
}
この特徴を持つ動物。

理解を容易にするために、クラス名を英語で示しました。これは Java では許可されていますが、非常に望ましくありません。













私たちにはFish話す能力がありません(CanSpeakインターフェースを実装していません)。

public static void main(String[] args)
{
   // Add all the animals to the list
   ArrayList pets = new ArrayList();
   pets.add(new Cat());
   pets.add(new Dog());
   pets.add(new Fish());

   // If the ability exists, then make a sound
   for(Object pet: pets)
   {
      if (pet instanceof CanSpeak)
      {
         CanSpeak loudmouth = (CanSpeak) pet;
         loudmouth.speak();
      }
   }
}
そして、どうやって彼らに命令を与えるのでしょうか?

プログラム内のクラスの数が数千に達すると、インターフェイスなしでは生きていけなくなります。何千ものクラスの相互作用を説明する代わりに、数十のインターフェースの相互作用を説明するだけで十分です。これにより、作業が大幅に簡素化されます。

そして、ポリモーフィズムと組み合わせると、このアプローチは通常、大成功を収めます。



3.defaultインターフェースメソッドの実装

抽象クラスは変数とメソッドの実装を持つことができますが、多重継承を持つことはできません。インターフェイスには変数やメソッドの実装を含めることはできませんが、多重継承は可能です。

状況を次の表に示します。

能力・財産 抽象クラス インターフェース
変数
メソッドの実装
多重継承

そのため、一部のプログラマは、インターフェイスにメソッド実装機能を持たせることを本当に望んでいました。ただし、メソッド実装を追加できるからといって、必ずメソッド実装が追加されるわけではありません。必要に応じて追加してください。あるいは、そうでない場合は、しないでください。

さらに、多重継承の問題は主に変数が原因で発生します。いずれにせよ、それが彼らが決定し、実行したことです。JDK 8 以降、Java にはメソッド実装をインターフェースに追加する機能が導入されました。

更新された表は次のとおりです (JDK 8 以降の場合)。

能力・財産 抽象クラス インターフェース
変数
メソッドの実装
多重継承

抽象クラスとインターフェイスについては、実装の有無にかかわらずメソッドを宣言できるようになりました。そしてこれは素晴らしいニュースです!

抽象クラスでは、実装のないメソッドの前にabstractキーワードを付ける必要があります。実装ではメソッドの前に何も追加する必要はありません。インターフェイスではその逆が当てはまります。メソッドに実装がない場合は、何も追加する必要はありません。ただし、実装がある場合は、defaultキーワードを追加する必要があります。

わかりやすくするために、この情報を次の小さな表に示します。

能力・財産 抽象クラス インターフェース
実装されていないメソッド abstract
実装を伴うメソッド default

問題

メソッドを持つインターフェイスを使用すると、大規模なクラス階層を大幅に簡素化できます。たとえば、抽象InputStreamおよびOutputStreamクラスはインターフェイスとして宣言できます。これにより、より頻繁に、より便利に使用できるようになります。

しかし、世界中にはすでに数千万 (数十億?) の Java クラスが存在します。また、標準ライブラリを変更し始めると、何かが壊れる可能性があります。すべてが好きです!😛

既存のプログラムやライブラリを誤って壊さないようにするために、インターフェイス内のメソッド実装の継承優先順位は最も低いものとすることが決定されました。

たとえば、あるインターフェイスがメソッドを持つ別のインターフェイスを継承し、最初のインターフェイスが同じメソッドを宣言しているが実装がない場合、継承されたインターフェイスからのメソッド実装は継承インターフェイスに到達しません。例:

interface Pet
{
   default void meow()
   {
      System.out.println("Meow");
   }
}

interface Cat extends Pet
{
   void meow(); // Here we override the default implementation by omitting an implementation
}

class Tom implements Cat
{
}

Tomクラスがメソッドを実装していないため、コードはコンパイルされませんmeow()