3秒でわかる
実装を持たないメソッドの約束事だけを並べたJavaの型。実装クラスを後から差し替えても呼び出し側のコードを書き換えずに済ませるために使います。
もう少し詳しく
どういうものか
Java のインターフェースは「このメソッドを持っていること」という約束だけを並べた型です。interface キーワードで宣言し、使う側のクラスは implements を付けて、宣言されたメソッドをすべて実装します。フィールドは暗黙に public static final の定数だけ、メソッドは本体を持たないのが基本形です。Java 8 以降は default メソッドで共通実装を、static メソッドでユーティリティを持たせられるようになりましたが、状態(インスタンス変数)は持てないという線引きは変わっていません。
なぜ必要か
インターフェースが無いと、呼び出す側は具体的なクラス名を直接書くことになります。決済処理でクレジットカード決済クラスを直接 new していると、後からコンビニ払いを足すたびに呼び出し側の分岐が増えていきます。「支払える」という約束だけに依存しておけば、増えるのは実装クラスだけで、呼び出し側は触らずに済みます。Spring Boot の DI が「型で注入する」形になっているのも、テスト時に本物の実装をモックへ差し替えられるようにするためです。
具体例
interface PaymentMethod {
boolean pay(int amount);
}
class CreditCard implements PaymentMethod {
public boolean pay(int amount) {
System.out.println("カードで " + amount + " 円");
return true;
}
}
class ConvenienceStore implements PaymentMethod {
public boolean pay(int amount) {
System.out.println("コンビニ払いで " + amount + " 円");
return true;
}
}
class Checkout {
// 引数の型がインターフェースなので、どちらの実装でも受け取れる
void run(PaymentMethod method, int amount) {
method.pay(amount);
}
}似た用語との違い
| 比べる点 | インターフェース | 抽象クラス |
|---|---|---|
| いくつ持てるか | 複数 implements できる | extends は 1 つだけ |
| 状態 | インスタンス変数を持てない | フィールドを持てる |
| コンストラクタ | 無い | 書ける |
| 向いている場面 | 能力の約束を横断的に付ける | 共通の土台を継承で配る |
つまずきやすいところ
実装クラスでメソッドの綴りを間違えても、@Override を付けていないとコンパイルエラーの内容が「抽象メソッドが実装されていない」という遠い場所の指摘になり、原因を探しにくくなります。実装メソッドには必ず @Override を付けておくと、綴り違いや引数違いをその行で止められます。もう一つ多いのが、インターフェースのメソッドを public 以外にしようとして怒られるパターンです。インターフェースのメソッドは暗黙に public なので、実装側で public を外すとアクセス修飾子を弱めたことになりコンパイルが通りません。