インタフェースは抽象メソッドと定数のみを持ち、究極的な抽象クラスのようなものと言える。インタフェースは「特定の機能」を表すが、実際の処理内容の詳細は規定しない。実際の処理内容は、インタフェースを実装するクラスに任されている。
※ ただし、Java 8 から、インタフェースには static メソッドとメソッドのデフォルト実装が定義できるようになった。
Javaでは、複数のクラスを継承して新しいクラスを作ること、多重継承、はできない。しかし、複数のインタフェースを実装することができる。
抽象メソッドと定数のみから構成される。
インタフェースは class ではなく interface を使って指定する。書式は
interface インタフェース名 { ‥‥ 定数の宣言 ‥‥ ‥‥ メソッドの宣言 ‥‥ }
である。メソッドは
型名 メソッド名 ( パラメータの並び ) ;
の形で、本体を記述せずに定義する。
インタフェースの中のメソッドはすべて public な抽象メソッドである。public や abstract をつける必要はないが、明示しても構わない。
※ ただし、Java 8 からのメソッドのデフォルト実装をする場合は、default キーワードをつけて
default 型名 メソッド名 ( パラメータの並び ) { ... デフォルトの処理 ... }
の形で、デフォルト実装を持つメソッドを定義できる。また、
static 型名 メソッド名 ( パラメータの並び ) { ... 処理 ... }
の形で、staticメソッドを定義できる。
定数は
型名 定数名 = 値 ;
の形で値を指定して定義する。
インタフェースの中で定義される変数はすべて public static final な定数である。public, static, final をつける必要はないが、明示しても構わない。全部明示する場合は、
public static final 型名 定数名 = 値 ;
のようになる。
インタフェースを使う側のクラスでは、クラスの宣言の際に implements を使ってインタフェースを指定する。こちらのクラスではインタフェースで宣言されているすべての抽象メソッドの中味を記述する必要がある。これをインタフェースの 実装 (implementation) と言う。
class クラス名 implements インタフェース名 { ‥‥ インタフェースの抽象メソッドの実装 ‥‥ }
上記クラスの中では、当然だが、自身で実装したメソッドを利用できる。
一方、インタフェースに含まれる定数は
定数名
だけを指定することで利用できる。一般のクラスの static 変数の場合だと
クラス名.変数名
の形で指定するが、インタフェースの定数はインタフェース名をつけずに指定することに注意。以下のようにカンマで区切って複数指定すれば、複数のインタフェースを実装できる。
class クラス名 implements インタフェース1, インタフェース2, インタフェース3 { ‥‥ インタフェース1の抽象メソッドの実装 ‥‥ ‥‥ インタフェース2の抽象メソッドの実装 ‥‥ ‥‥ インタフェース3の抽象メソッドの実装 ‥‥ }
アノテーションの利用
Java 6 以降では、メソッドの実装の際に
@Override
というアノテーション (注釈) を入れることが推奨されている。
メソッドを間違えて、実装あるいはオーバーライドできないメソッドに @Override を入れるとエラーになるので、プログラムの保守性が良くなる。
インタフェースには実体がないのでインスタンスを持つことはできない。しかし、インタフェースを型として指定することで、そのインタフェースを実装している任意のクラスのインスタンスを指定できる。つまり
インタフェース名 変数名;
は
class 任意のクラス implements インタフェース名 { ‥‥ 抽象メソッドの実装 ‥‥ } 任意のクラス 変数名;
に相当すると考えればよい。ただ、同等ではなく、インタフェース名を型とする変数では、そのインタフェースで定義されているメソッドしか呼び出すことができない。
(例)
インタフェース java.lang.Runnable (単に Runnable として利用できる) は run() というメソッドを持つインタフェースで、以下のように定義されていると考えられる。
package java.lang; public interface Runnable { public void run(); }
※ 上はあくまで想定コード。
この Runnable インタフェースを実装したクラスのインスタンスが必要なときは、例えば、無名クラスの記法を使って
Runnable r = new Runnable() { @Override public void run() { for ( int i = 1; i <= 10; ++i ) { System.out.print( " " + i ); } System.out.println(); } };
とする。この Runnable を実装したインスタンス r は以下のように Thread (java.lang.Thread クラス) から利用できる。
new Thread( r ).start();
Thread クラスは Java の実行の単位 スレッド を表す。生成されたスレッドは start() メソッドにより実行が開始され、 Runnable を実装したインスタンス r の run() を実行し停止する。
上例では、スペース区切りの 1 から 10 までの数字と改行を標準出力に出力し停止する。
インタフェースを基にして新しいインタフェースを作ることができる。これをインタフェースの継承と言う。インタフェースの継承はクラスの継承と同じく extends というキーワードを使って基のインタフェースを指定する。
interface Ai { ‥‥‥ } interface Bi extends Ai { ‥‥‥ }
新しく定義されたインタフェース Bi は基となったインタフェース Ai の サブインタフェース (subinterface) と言う。
また、基となったインタフェース Ai は新しく定義されたインタフェース Bi の スーパーインタフェース (superinterface) と言う。
インタフェース Bi を実装するクラスでは、インタフェース Bi で宣言されているメソッドを実装するだけでなく、スーパーインタフェース Ai で宣言されているメソッドもすべて実装する必要がある。
クラスでは多重継承はできないが、インタフェースは多重継承できる。その場合は extends の後にスーパーインタフェースをコンマで区切って並べる。
interface Ai { ‥‥‥ } interface Bi { ‥‥‥ } interface Ci { ‥‥‥ } interface Di extends Ai, Bi, Ci { ‥‥‥ }
インタフェース Di を実装するクラスでは、インタフェース Di の中で宣言されているメソッドを実装するだけでなく、スーパーインタフェース Ai および Bi および Ci で宣言されているメソッドをすべて実装する必要がある。