Menu
Coddy logo textTech

インターフェースのデフォルトと静的メソッド

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つのインターフェースを実装する場合、そのクラスは競合を解決するためにそのメソッドをオーバーライドしなければなりません。

challenge icon

チャレンジ

簡単

インターフェースにおけるデフォルトメソッドと静的メソッドの両方を活用したメッセージングシステムを構築しましょう。実装クラスが直接使用したり、必要に応じてカスタマイズしたりできる組み込み機能を備えたインターフェースを作成します。

コードは以下の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() を呼び出す
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン