インターフェースのデフォルトと静的メソッド
CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 37/87。
元来、インターフェースは実装を持たない抽象メソッドのみを含むことができました。Java 8以降、インターフェースはデフォルトメソッドと静的メソッドを含めることができるようになり、より柔軟になりました。
デフォルトメソッドは、defaultキーワードを使用して、インターフェース内で直接実装を提供します。インターフェースを実装するクラスは、この振る舞いを自動的に継承しますが、必要に応じてオーバーライドすることもできます:
public interface Drawable {
void draw();
default void display() {
System.out.println("Displaying on screen...");
draw();
}
}Drawableを実装するすべてのクラスは、display()メソッドをそのまま利用できます。これは、すでにインターフェースを実装しているクラスを壊すことなく、既存のインターフェースに新しいメソッドを追加する際に特に便利です。
インターフェースの静的メソッドは、クラスの静的メソッドと同じように動作します。これらはインターフェース自体に属し、インターフェース名を使用して呼び出されます:
public interface MathOperations {
static int add(int a, int b) {
return a + b;
}
}
// 使用例
int result = MathOperations.add(5, 3);インターフェースの静的メソッドはオーバーライドできず、実装クラスに継承されることもありません。これらは、インターフェースの目的に関連するユーティリティメソッドに役立ちます。
クラスが同じデフォルトメソッドのシグネチャを持つ2つのインターフェースを実装する場合、そのクラスは競合を解決するためにそのメソッドをオーバーライドしなければなりません。
チャレンジ
簡単インターフェースにおけるデフォルトメソッドと静的メソッドの両方を活用したメッセージングシステムを構築しましょう。実装クラスが直接使用したり、必要に応じてカスタマイズしたりできる組み込み機能を備えたインターフェースを作成します。
コードは以下の4つのファイルに分けて構成します:
Messenger.java: あらゆるメッセージングサービスを表すインターフェースを定義します。戻り値が void の抽象メソッドsendMessage(String message)を宣言してください。[TIMESTAMP]と出力した後にsendMessage(message)を呼び出す、sendWithTimestamp(String message)という名前のデフォルトメソッドを追加します。また、メッセージを大文字に変換して返すformatMessage(String message)という名前の静的メソッドも含めてください。EmailMessenger.java:Messengerを実装するクラスを作成します。recipientフィールド(String)を持ちます。受信者を初期化するためのコンストラクタを含めてください。sendMessage()を実装し、Email to [recipient]: [message]と出力するようにします。このクラスは、デフォルトのsendWithTimestamp()メソッドをそのまま使用します。SMSMessenger.java:Messengerを実装する別のクラスを作成します。phoneNumberフィールド(String)を持ちます。電話番号を初期化するためのコンストラクタを含めてください。sendMessage()を実装し、SMS to [phoneNumber]: [message]と出力するようにします。デフォルトのsendWithTimestamp()メソッドをオーバーライドし、デフォルトのタイムスタンプ動作の代わりに[URGENT]と出力してからsendMessage(message)を呼び出すようにします。Main.java: すべてを組み合わせて、インターフェースのデフォルトメソッドと静的メソッドの両方を実演します。メールの受信者、電話番号、メッセージの3つの入力を受け取ります。まず、静的メソッドMessenger.formatMessage()を使用してメッセージをフォーマットし、保存します。次に、EmailMessenger と SMSMessenger を作成します。各メッセンジャーに対して、フォーマットされたメッセージを引数にsendWithTimestamp()を呼び出します。EmailMessenger がデフォルトの実装を使用し、SMSMessenger がオーバーライドされたバージョンを使用することを確認してください。
入力として、メールの受信者(String)、電話番号(String)、メッセージ(String)の3つを受け取ります。
出力は、各メッセンジャーにつき2行ずつ、計4行になるはずです。EmailMessenger はデフォルトのタイムスタンプのプレフィックスを表示し、SMSMessenger はカスタムの緊急(urgent)プレフィックスを表示します。どちらも静的にフォーマットされた(大文字の)メッセージを使用します!
チートシート
Java 8以降、インターフェースには抽象メソッドに加えて、デフォルトメソッドと静的メソッドを含めることができるようになりました。
デフォルトメソッドは、defaultキーワードを使用してインターフェース内で直接実装を提供します。インターフェースを実装するクラスは、この動作を自動的に継承しますが、必要に応じてオーバーライドすることもできます。
public interface Drawable {
void draw();
default void display() {
System.out.println("Displaying on screen...");
draw();
}
}インターフェース内の静的メソッドはインターフェース自体に属し、インターフェース名を使用して呼び出されます。これらはオーバーライドできず、実装クラスに継承されることもありません。
public interface MathOperations {
static int add(int a, int b) {
return a + b;
}
}
// 使用例
int result = MathOperations.add(5, 3);クラスが同じデフォルトメソッドのシグネチャを持つ2つのインターフェースを実装する場合、そのクラスは競合を解決するためにそのメソッドをオーバーライドする必要があります。
自分で試してみよう
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 入力を読み込む
String emailRecipient = scanner.nextLine();
String phoneNumber = scanner.nextLine();
String message = scanner.nextLine();
// TODO: Messenger.formatMessage() を使用してメッセージをフォーマットし、保存する
// TODO: emailRecipient を使用して EmailMessenger を作成する
// TODO: phoneNumber を使用して SMSMessenger を作成する
// TODO: フォーマットされたメッセージを使用して、EmailMessenger の sendWithTimestamp() を呼び出す
// TODO: フォーマットされたメッセージを使用して、SMSMessenger の sendWithTimestamp() を呼び出す
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4継承
継承の基本 (extends)super キーワードメソッドのオーバーライド (@Override)コンストラクタチェーンObject クラス単一継承と多段階継承なぜ多重継承ができないのかまとめ:従業員の階層構造6インターフェースと抽象クラス
インターフェース入門インターフェースの実装複数インターフェースの実装インターフェースのデフォルトと静的メソッド抽象クラス vs インターフェース関数型インターフェースまとめ - 決済システム