Menu

Java のインターフェース: 契約の定義と implements

Java のインターフェースとは何か、その定義と実装の方法、default メソッドと static メソッド、そしてインターフェースが抽象クラスとどう異なるかを解説します。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

インターフェースは契約

インターフェースは、クラスがどのように行うかを述べずに、何をできるかを宣言します。これは、実装するどのクラスも満たすと約束するメソッドシグネチャのリストです。要点は分離です。コードはインターフェース型を扱えばよく、その背後にどの具象クラスがあるかを気にする必要はありません。

Circle implements Shape は、Circleareaperimeter を定義しなければならないことを意味します。定義してしまえば、CircleShape であるため、Shape 型の変数に格納できます。

多くのクラス、1 つの型

その威力は、無関係な複数のクラスが同じインターフェースを実装したときに現れます。Shape に対して書かれたコードは、それらすべてを扱えます。

このループは「これは Circle なのか Rectangle なのか?」とは一切尋ねません。単に area() を呼び出して契約を信頼します。後で Triangle を追加しても、ここでは何の変更も要りません。

複数のインターフェースの実装

クラスが継承できるクラスは 1 つだけですが、実装できるインターフェースの数に制限はありません。これが、Java が振る舞いの「多重継承」を安全に行う方法です。

インターフェースは implements の後にカンマ区切りで並べます。クラスはそのすべてを満たさなければなりません。

default メソッドと static メソッド

Java 8 以降、インターフェースはメソッド本体を持てます。default メソッドは、実装クラスが無償で継承する(そしてオーバーライドできる)既製の実装を与えます。

default メソッドはインターフェースの進化を可能にします。既存のすべての実装者を壊すことなくメソッドを追加できます。対照的に static インターフェースメソッドは、Comparator.naturalOrder() のように、インターフェース自体に対して呼び出すユーティリティです。

定数

インターフェースのフィールドは暗黙的に public static final です。これらは定数であり、インスタンスの状態ではありません。

interface Physics {
    double GRAVITY = 9.81;   // automatically public static final
}

インターフェースは伝統的にオブジェクトごとの状態を持ちません。インスタンスフィールドがないことは、インターフェースをクラスと区別する要素の 1 つです。

関数型インターフェース

抽象メソッドをちょうど 1 つだけ持つインターフェースは関数型インターフェースであり、クラス全体ではなくラムダ式で実装できます。

これは Java のラムダと java.util.function の型(FunctionPredicateSupplier など)の基盤です。@FunctionalInterface アノテーションは意図を明示し、コンパイラに単一メソッドのルールを強制させます。

インターフェース vs 抽象クラス

どちらも抽象に対してプログラミングできますが、どちらをいつ選ぶべきでしょうか?

  • インターフェース - 無関係なクラスが共有できる能力。BirdAirplane はどちらも Flyable になれます。クラスは多数を実装できます。インスタンスの状態はありません。
  • 抽象クラス - 密接に関連したクラス間で共有される状態とコード。CatDog はどちらも Animal を継承し、共通のフィールドと部分的に実装されたメソッドを引き継ぎます。クラスは 1 つだけ継承します。

よくあるパターンはこの 2 つを組み合わせます。インターフェースが契約を定義し、抽象クラスが定型部分を実装することで、具象サブクラスは固有の部分だけを埋めればよくなります。

次: 抽象クラス

インターフェースは状態を持たずに振る舞いを定義します。抽象クラスはインターフェースと完全なクラスの中間に位置し、未実装のメソッドを宣言でき、なおかつフィールドとコンストラクタを持てます。それが次のページのテーマです。

よくある質問

Java のインターフェースとは何ですか?

インターフェースは契約です。つまり、あるクラスが提供すると約束するメソッドシグネチャ(と定数)の集まりです。クラスが何をできるかを示し、どのように行うかは示しません。クラスは implements キーワードを使ってインターフェースを取り込み、インターフェースが宣言するすべての抽象メソッドに本体を与えなければなりません。インターフェースを使うと、無関係なクラスどうしを共通の型を通じて互換的に扱えます。

Java におけるインターフェースと抽象クラスの違いは何ですか?

クラスは複数のインターフェースを実装できますが、継承(extends)できる(抽象)クラスは 1 つだけです。インターフェースは伝統的にインスタンスの状態を持たず振る舞いだけを宣言しますが、抽象クラスはフィールド、コンストラクタ、部分的に実装されたロジックを持てます。無関係な複数のクラスが共有できる能力を定義したいときはインターフェースを使い、密接に関連したサブクラス間で共通の状態とコードを共有したいときは抽象クラスを使います。

Java のインターフェースはメソッド本体を持てますか?

はい、Java 8 以降は可能です。default と付けられたインターフェースメソッドは、実装クラスが継承する(そしてオーバーライドできる)本体を提供し、static インターフェースメソッドはインターフェース自体に対して呼び出せるユーティリティ的な振る舞いを提供します。通常のインターフェースメソッドは依然として抽象的で -シグネチャだけ- 実装クラスがそれらを定義しなければなりません。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める