CodeGym /コース /JAVA 25 SELF /インターフェースの概念と宣言の構文

インターフェースの概念と宣言の構文

JAVA 25 SELF
レベル 20 , レッスン 0
使用可能

1. インターフェースとは?

抽象クラスが家の設計図だとすれば、インターフェースはむしろ特定の作業を行うという「契約」に近いものです。たとえば、水道工事を依頼するとき、あなたは「蛇口を直す」「漏れを止める」といったことができると期待します。どうやって実現するかは気にしません。結果が出れば十分です。Java におけるインターフェースはまさにその契約であり、どのメソッドを実装すべきかは定めるものの、どのように実装するかは規定しません。

要点だけ簡潔に:

インターフェースは、Java の特別な型で、そのインターフェースに「サイン」したクラスが実装しなければならないメソッド群を定義します。

  • インターフェースは「何をするか」だけを記述し、「どうやってするか」は記述しません。
  • Java 8 までは、インターフェースにメソッドの実装は含まれませんでした。
  • インターフェースは純粋な契約です。クラスがインターフェースを実装するなら、そのすべてのメソッドを実装する必要があります。

なぜ便利なのか?

  • 1 つのクラスに複数のインターフェースを「付与」でき、複数の「役割」を与えられます。
  • クラスがさまざまな機能を実装できるため、柔軟で拡張可能なアーキテクチャを構築できます。
  • インターフェースは Java の標準ライブラリで広く使われています(例: ComparableSerializableRunnable など)。

2. インターフェースの宣言構文

Java でインターフェースを宣言するのはとても簡単です。キーワード interface を使います。Java 8 までは、インターフェースのメソッドは明示しなくてもデフォルトで public abstract と見なされました。つまり、そのインターフェースを実装するクラスでメソッドを実装しなければならない、ということです。

インターフェースの例


public interface Movable {
    void move(int x, int y);
}
  • ここではインターフェース Movable を宣言しています(「動かせる」「動く能力をもつ」といった意味に訳せます)。
  • 内部にはメソッド move(int x, int y) が宣言されています。メソッド本体はなく、シグネチャのみです。これが「契約」です。すなわち「Movable を実装するなら、move を実装しなさい」ということです。

構文上の特徴

  • インターフェースのメソッドは(Java 8 までは)本体を持ちません
  • インターフェースのすべてのメソッドはデフォルトで public abstract(明示不要)です。
  • インターフェースには定数(public static final)のみを含められ、通常のフィールドは持てません。

定数の例

public interface Constants {
    int MAX_SPEED = 100; // 既定で public static final
}

3. インターフェースとクラスの違い

インターフェースはクラスではありません! その違いを整理しましょう。

クラス(抽象クラスを含む) インターフェース
フィールド(状態)を持てる フィールドは持てない(定数のみ)
メソッドの実装を含められる Java 8 までは実装を含められず、シグネチャのみ
new で生成できる(抽象でなければ) 直接は生成できない
継承は 1 つだけ(extends クラスは複数のインターフェースを実装できる(implements
「それは何か」を表す 「何ができるか」を表す

クラスは次のようにしてインターフェースを実装します: implements

public class Robot implements Movable {
    @Override
    public void move(int x, int y) {
        System.out.println("ロボットは座標 (" + x + ", " + y + ") に移動します");
    }
}
  • Robot クラスは Movable インターフェースを実装しています。
  • キーワード implements は「実装する」の意味です。
  • インターフェースのすべてのメソッドを実装する必要があります(実装しないとコンパイルエラー)。
  • アノテーション @Override を忘れずに。必須ではありませんが、コンパイラやあなた自身のミス防止に役立ちます。

4. インターフェースの使用例

シンプルな例を書いて、実際の動きを見てみましょう。インターフェース Movable があり、ロボット、車、動物など、さまざまなクラスが「動ける」ようにしたいとします。

ステップ 1. インターフェースを宣言する

public interface Movable {
    void move(int x, int y);
}

ステップ 2. クラスでインターフェースを実装する

public class Robot implements Movable {
    @Override
    public void move(int x, int y) {
        System.out.println("ロボットは座標 (" + x + ", " + y + ") に移動します");
    }
}

ステップ 3. インターフェースを使う

public class Main {
    public static void main(String[] args) {
        Movable m = new Robot(); // インターフェース型の変数!
        m.move(10, 20); // 出力: ロボットは座標 (10, 20) に移動します
    }
}

注意

  • インターフェース型の変数(Movable m)を宣言し、そのインターフェースを実装したクラスのオブジェクト(new Robot())を代入できます。
  • これにより、実際のクラスが何であるかを知らなくても、あらゆる「動ける」オブジェクトで動作する汎用的なコードが書けます。

メソッドを実装しない場合のコンパイルエラー

Error: Class 'Robot' must either be declared abstract or implement abstract method 'move(int, int)' in 'Movable'

これこそがインターフェースの力です。インターフェースは、すべての実装クラスが必要なメソッドを保証するのです。

5. Java 標準ライブラリのインターフェース

インターフェースは単なる「学校の話題」ではありません。Java の標準ライブラリ全体で積極的に使われています。いくつか例を挙げます。

  • Comparable<T> — オブジェクトを比較するためのインターフェース(たとえばソート時)。
  • Runnable — スレッドを起動するためのインターフェース。
  • Serializable — オブジェクトがシリアライズ可能であることを示すマーカーインターフェース。
  • ListSetMap — コレクションのインターフェース。

例: Comparable

public class Person implements Comparable<Person> {
    String name;
    int age;

    // コンストラクターやその他のメソッド...

    @Override
    public int compareTo(Person other) {
        return this.age - other.age;
    }
}

これで、Person オブジェクトは Comparable を実装しているため、ソートできます。

6. ビジュアル図: インターフェースはどのように機能するか

+-------------------+         +-------------------+
|   interface       |         |    class          |
|   Movable         |<--------|    Robot          |
|-------------------|         |-------------------|
| +move(int, int)   |         | +move(int, int)   |
+-------------------+         +-------------------+
  • 矢印は、クラス Robot がインターフェース Movable を実装していることを示しています。
  • インターフェースは「何が必要か」だけを定義し、クラスは「どのように動作するか」を定義します。

身近な例え

Java のインターフェースは運転免許のようなものです。もしあなたが免許(「運転者」インターフェースを実装)を持っているなら、車を運転できるということです。具体的にどう運転するかは人それぞれです。丁寧に運転する人もいれば、速く運転する人もいます。しかし重要なのは、「運転できる」と約束している点です。

7. 実用例: アプリを拡張する

public interface Movable {
    void move(int x, int y);
}

public class Animal implements Movable {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    @Override
    public void move(int x, int y) {
        System.out.println(name + " は座標 (" + x + ", " + y + ") に移動します");
    }
}

public class Robot implements Movable {
    private String model;

    public Robot(String model) {
        this.model = model;
    }

    @Override
    public void move(int x, int y) {
        System.out.println("ロボット " + model + " が座標 (" + x + ", " + y + ") に向かって進みます");
    }
}

public class Main {
    public static void main(String[] args) {
        Movable[] movables = {
            new Animal("Barsik"),
            new Robot("R2D2")
        };

        for (Movable m : movables) {
            m.move(5, 10);
        }
    }
}

結果:

Barsik は座標 (5, 10) に移動します
ロボット R2D2 が座標 (5, 10) に向かって進みます

Movable 型のオブジェクト配列を作成しました。そこには、このインターフェースを実装する任意のオブジェクトを入れられます! ループ内のコードは、相手が動物かロボットかを知りませんが、どちらも move できることは分かっています。

8. インターフェースでよくあるミス

ミス No. 1: インターフェースのオブジェクトを直接作ろうとする。 インターフェースは契約であって、具体的なオブジェクトではありません。new Movable() のように書くことはできず、コンパイルエラーになります。インターフェースを実装したクラスのオブジェクトを作成する必要があります。

ミス No. 2: インターフェースのすべてのメソッドを実装していない。 クラスがインターフェースを実装しているのに、すべてのメソッドを実装していない場合、コンパイラは「Class must either be declared abstract or implement abstract method ...」というエラーを出します。すべて実装したくないなら、クラスを abstract として宣言してください。

ミス No. 3: アクセス修飾子を忘れる。 インターフェースのメソッドは常に public(明示しなくても)です。実装クラスではアクセスレベルを下げることはできないため、メソッドも public にする必要があります。

ミス No. 4: 通常のフィールドをインターフェースに追加しようとする。 インターフェースで宣言できるのは定数(public static final)のみです。通常(非 static)のフィールドは追加できません。

コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION