Java インターフェース

インターフェース(英語:Interface)は、JAVAプログラミング言語における抽象型であり、抽象メソッドの集合です。インターフェースは通常、interface キーワードで宣言されます。クラスはインターフェースを実装することによって、インターフェースの抽象メソッドを継承します。

インターフェースはクラスではありません。インターフェースの記述方法はクラスとよく似ていますが、それらは異なる概念です。クラスはオブジェクトの属性とメソッドを記述します。インターフェースは、クラスが実装すべきメソッドを含みます。

インターフェースを実装するクラスが抽象クラスでない限り、そのクラスはインターフェース内のすべてのメソッドを定義しなければなりません。

インターフェースはインスタンス化できませんが、実装することはできます。インターフェースを実装するクラスは、インターフェース内で記述されたすべてのメソッドを実装しなければならず、そうでなければ抽象クラスとして宣言する必要があります。また、Java では、インターフェース型を使って変数を宣言でき、その変数はヌルポインタになることも、このインターフェースを実装したオブジェクトにバインドされることもできます。

インターフェースとクラスの類似点:

  • 1つのインターフェースは複数のメソッドを持つことができます。
  • インターフェースファイルは .java で終わるファイルに保存され、ファイル名にはインターフェース名を使用します。
  • インターフェースのバイトコードファイルは .class で終わるファイルに保存されます。
  • インターフェースに対応するバイトコードファイルは、パッケージ名に対応するディレクトリ構造内に置く必要があります。

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

  • インターフェースはオブジェクトのインスタンス化には使用できません。
  • インターフェースにはコンストラクタがありません。
  • インターフェース内のすべてのメソッドは抽象メソッドでなければなりません。Java 8 以降は、インターフェース内で default キーワードで修飾された非抽象メソッドを使用できます。
  • インターフェースは、static 変数と final 変数を除いて、メンバー変数を含めることはできません。
  • インターフェースはクラスに継承されるのではなく、クラスによって実装されるものです。
  • インターフェースは多重継承をサポートします。

インターフェースの特性

  • インターフェース内の各メソッドも暗黙的に抽象であり、インターフェース内のメソッドは暗黙的に次のように指定されます。public abstract(public abstract のみ可能で、他の修飾子はエラーになります)。
  • インターフェースには変数を含めることができますが、インターフェース内の変数は暗黙的に次のように指定されます。public static final変数(かつ public のみ可能で、private で修飾するとコンパイルエラーになります)。
  • インターフェース内のメソッドはインターフェース内で実装することはできず、インターフェースを実装するクラスだけがインターフェース内のメソッドを実装できます。

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

  • 1. 抽象クラスのメソッドはメソッド本体を持つことができ、つまりメソッドの具体的な機能を実装できますが、インターフェースのメソッドはそれができません。
  • 2. 抽象クラスのメンバー変数は様々な型にすることができますが、インターフェースのメンバー変数はpublic static final型のみです。
  • 3. インターフェースは静的コードブロックおよび静的メソッド(static で修飾されたメソッド)を含むことはできませんが、抽象クラスには静的コードブロックと静的メソッドを含めることができます。
  • 4. 1つのクラスは1つの抽象クラスしか継承できませんが、1つのクラスは複数のインターフェースを実装できます。

注:JDK 1.8 以降、インターフェース内に静的メソッドとメソッド本体を持たせることができるようになりました。

注JDK 1.8 以降、インターフェースは具体的な実装を持つメソッドを含むことができます。このメソッドは「デフォルトメソッド」と呼ばれ、デフォルトメソッドは default キーワードで修飾されます。詳細は次を参照してください。Java 8 デフォルトメソッド。

注:JDK 1.9 以降、メソッドを private として定義できるようになり、一部の再利用コードがメソッドを外部に公開しないようにできます。詳細は次を参照してください。Java 9 プライベートインターフェースメソッド。


インターフェースの宣言

インターフェースの宣言構文は次のとおりです:

[可視性] interfaceインターフェース名[extends他のインターフェース名] { //変数の宣言 //抽象メソッド }

Interface キーワードはインターフェースを宣言するために使用します。以下はインターフェース宣言の簡単な例です。

NameOfInterface.java のファイルコード:

/*ファイル名 : NameOfInterface.java*/ import java.lang.*; //パッケージのインポート public interface NameOfInterface { //任意の型の final, static フィールド //抽象メソッド }
インターフェースには次の特性があります:
  • インターフェースは暗黙的に抽象です。インターフェースを宣言するとき、abstractキーワードを使用する必要はありません。
  • インターフェース内の各メソッドも暗黙的に抽象であり、宣言時にも同様に、abstractキーワードは必要ありません。
  • インターフェース内のメソッドはすべて public です。

例

Animal.java のファイルコード:

/*ファイル名 : Animal.java*/ interface Animal { public void eat(); public void travel(); }

インターフェースの実装

クラスがインターフェースを実装する場合、クラスはインターフェース内のすべてのメソッドを実装しなければなりません。そうでない場合、クラスは抽象クラスとして宣言する必要があります。

クラスは implements キーワードを使用してインターフェースを実装します。クラス宣言では、implements キーワードは class 宣言の後に置きます。

インターフェースを実装する構文は、次の公式を使用できます:

インターフェースの構文:

...implementsインターフェース名[, 他のインターフェース名, 他のインターフェース名..., ...] ...

例

MammalInt.java のファイルコード:

/*ファイル名 : MammalInt.java*/ public class MammalInt implements Animal{ public void eat(){ System.out.println("Mammal eats"); } public void travel(){ System.out.println("Mammal travels"); } public int noOfLegs(){ return 0; } public static void main(String args[]){ MammalInt m = new MammalInt(); m.eat(); m.travel(); } }

上記の例をコンパイルして実行した結果は次のとおりです:

Mammal eats
Mammal travels

インターフェースで宣言されたメソッドをオーバーライドする際には、以下の規則に注意する必要があります:

  • クラスがインターフェースのメソッドを実装するとき、強制例外をスローすることはできません。強制例外は、インターフェース内、またはインターフェースを継承する抽象クラス内でのみスローできます。
  • クラスはメソッドをオーバーライドするときに、メソッド名を一致させ、同じまたは互換性のある戻り値の型を維持する必要があります。
  • インターフェースを実装するクラスが抽象クラスである場合、そのインターフェースのメソッドを実装する必要はありません。

インターフェースを実装する際には、いくつかの規則にも注意する必要があります:

  • 1つのクラスは複数のインターフェースを同時に実装できます。
  • 1つのクラスは1つのクラスしか継承できませんが、複数のインターフェースを実装できます。
  • 1つのインターフェースは別のインターフェースを継承でき、これはクラス間の継承と似ています。

インターフェースの継承

1つのインターフェースは別のインターフェースを継承でき、その方法はクラス間の継承と似ています。インターフェースの継承は extends キーワードを使用し、子インターフェースは親インターフェースのメソッドを継承します。

以下の Sports インターフェースは Hockey と Football インターフェースに継承されています:

//ファイル名: Sports.java public interface Sports { public void setHomeTeam(String name); public void setVisitingTeam(String name); } //ファイル名: Football.java public interface Football extends Sports { public void homeTeamScored(int points); public void visitingTeamScored(int points); public void endOfQuarter(int quarter); } //ファイル名: Hockey.java public interface Hockey extends Sports { public void homeGoalScored(); public void visitingGoalScored(); public void endOfPeriod(int period); public void overtimePeriod(int ot); }

Hockey インターフェースはそれ自体で4つのメソッドを宣言し、Sports インターフェースから2つのメソッドを継承しています。したがって、Hockey インターフェースを実装するクラスは6つのメソッドを実装する必要があります。

同様に、Football インターフェースを実装するクラスは5つのメソッドを実装する必要があり、そのうち2つは Sports インターフェースから来ています。


インターフェースの多重継承

Java では、クラスの多重継承は許可されていませんが、インターフェースは多重継承を許可しています。

インターフェースの多重継承では、extends キーワードは一度だけ使用し、その後に継承するインターフェースを続けます。次のようになります:

public interface Hockey extends Sports, Event

上記のプログラム断片は、正当に定義された子インターフェースです。クラスとは異なり、インターフェースは多重継承を許可しており、Sports や Event は同じメソッドを定義または継承できます。


マーカーインターフェース

最も一般的なマーカーインターフェースは、メソッドをまったく含まないインターフェースです。

マーカーインターフェースは、メソッドも属性も持たないインターフェースです。それは単に、そのクラスが特定の型に属することを示し、他のコードが何かを行うことを許可するかどうかをテストするために使われます。

マーカーインターフェースの役割:簡単に言えば、あるオブジェクトにマーク(スタンプ)を付けて、そのオブジェクトに特定の特権を持たせることです。

例:java.awt.event パッケージ内の MouseListener インターフェースが継承する java.util.EventListener インターフェースの定義は次のとおりです:

package java.util; public interface EventListener {}

メソッドを持たないインターフェースはマーカーインターフェースと呼ばれます。マーカーインターフェースは主に以下の2つの目的で使用されます:

  • 共通の親インターフェースを確立する:

    EventListener インターフェースは、数十の他のインターフェースによって拡張されている Java API の例です。マーカーインターフェースを使用して、一連のインターフェースの親インターフェースを確立できます。例えば、あるインターフェースが EventListener インターフェースを継承すると、Java仮想マシン(JVM)はそのインターフェースがイベント委譲の仕組みに使用されることを認識します。

  • クラスにデータ型を追加する:

    これはマーカーインターフェースの当初の目的です。マーカーインターフェースを実装するクラスは、インターフェースメソッドを定義する必要はありません(マーカーインターフェースにはメソッドがないため)。しかし、そのクラスは多態性(ポリモーフィズム)によってインターフェース型になります。

その他の拡張