MEDIA

メディア

  1. TOP
  2. メディア
  3. プログラミング
  4. Javaのimplementsとは?インターフェース実装・extendsとの違い・実務活用まで徹底解説

Javaのimplementsとは?インターフェース実装・extendsとの違い・実務活用まで徹底解説

Javaの学習を進めると、class A implements B という構文に必ず直面します。しかし、多くの初心者がここで疑問を抱くのも事実です。

「継承(extends)と何が違うの?」
「なぜわざわざインターフェースを実装するの?」

このように感じるのは、implements が単なる「機能の継承」ではなく、「設計の契約」という意味合いが強いからです。

そこで本記事では、implements の基本的な構文から、抽象クラスとの明確な違い、そして現場で必須となる「疎結合な設計」への応用までを体系的に解説します。

implementsの基本:インターフェースを契約として扱う

まず結論から言えば、インターフェースとは「このクラスは、必ずこのメソッドを持っています」という契約書のようなものです。そして、その契約を守る(実装する)ためのキーワードが implements です。

具体的には、以下のような役割分担になります。

  • interface(インターフェース):メソッドの型(名前や引数)だけを定義し、中身は書かない(仕様書)
  • implements(実装):インターフェースで定義されたメソッドの中身を具体的に記述する(製造)

例えば、「動物(Animal)」というインターフェースを定義してみましょう。

基本的なコード例

まず、インターフェースを定義します。「鳴く(speak)」という機能を持つことを強制する仕様です。

// インターフェース定義
public interface Animal {
    // 具体的な処理は書かず、型だけ宣言する
    void speak();
}

次に、このインターフェースを implements を使って実装します。

// インターフェースを実装するクラス
public class Dog implements Animal {
    @Override
    public void speak() {
        // ここで初めて具体的な処理を書く
        System.out.println("ワン!");
    }
}

public class Cat implements Animal {
    @Override
    public void speak() {
        System.out.println("ニャー!");
    }
}

このように、implements Animal と宣言したクラスは、必ず speak() メソッドを実装しなければなりません。もし実装し忘れると、コンパイルエラーが発生します。

参考リンク:Oracle公式 Java インターフェース解説

implementsを使う3つの明確なメリット

では、なぜ直接クラスにメソッドを書かず、わざわざインターフェースを経由するのでしょうか。主な理由は以下の3点です。

  1. 実装の強制(契約の保証)
    「メソッド名の書き間違い」や「実装漏れ」を防ぎ、チーム開発での規格を統一できます
  2. 多重実装が可能
    Javaのクラス継承(extends)は1つしかできませんが、インターフェースは複数実装(implements A, B)が可能です
  3. ポリモーフィズム(多態性)の実現
    「犬」も「猫」も、プログラム上は同じ「動物(Animal)」として扱えるようになります

特に3つ目の「ポリモーフィズム」は重要です。以下のように、異なるクラスを同一の型として処理できます。

Animal myDog = new Dog();
Animal myCat = new Cat();

// どちらもAnimal型として扱える
myDog.speak(); // "ワン!"
myCat.speak(); // "ニャー!"

インターフェースと抽象クラスの違い

一方で、よく混同されるのが「抽象クラス(abstract class)」です。どちらも「抽象メソッド」を持てますが、役割と制約が異なります。

以下の表で主な違いを整理しました。

項目 インターフェース (interface) 抽象クラス (abstract)
目的 機能の「契約」を定義する
(CAN-DOの関係)
共通処理の「ひな形」を作る
(IS-Aの関係)
多重継承 可能 (implements A, B) 不可 (extendsは1つのみ)
フィールド 定数のみ (static final) 通常の変数も保持可能
メソッド 基本は抽象メソッド
(Java8以降 default可)
通常メソッドと抽象メソッドを混在可

したがって、使い分けの基準は以下のようになります。

  • interface:クラスの階層に関係なく、「機能」を付与したい場合(例:Runnable, Serializable
  • abstract class:親子関係があり、基本動作を共通化したい場合(例:BaseService

実務的な使い方とDI(依存性注入)

ここからは、現場レベルでの活用法を見ていきましょう。実務では、implements は「疎結合(Loose Coupling)」を実現するために不可欠です。

特に Spring Boot などのフレームワークでは、DI(依存性注入)と組み合わせて頻繁に使用されます。

通知サービスの設計例

例えば、ユーザーへの通知機能を開発するとします。最初はメール通知だけだったとしても、将来的にLINEやSlack通知が増える可能性があります。

そこで、具体的なクラスに依存せず、インターフェースに依存するようにコードを書きます。

// 1. 共通インターフェース
public interface NotificationService {
    void send(String message);
}

// 2. メールでの実装
public class EmailService implements NotificationService {
    public void send(String message) {
        System.out.println("Email送信: " + message);
    }
}

// 3. LINEでの実装
public class LineService implements NotificationService {
    public void send(String message) {
        System.out.println("LINE送信: " + message);
    }
}

利用側のコード(ビジネスロジック)

重要なのは、通知を利用する側のクラスが、EmailServiceLineService を直接知らなくて良い点です。

public class UserManager {
    // 具体的なクラスではなく、インターフェース型で保持する
    private final NotificationService notifier;

    // コンストラクタで実装を受け取る(DI)
    public UserManager(NotificationService notifier) {
        this.notifier = notifier;
    }

    public void registerUser() {
        // 具体的な手段(メールかLINEか)を気にせず実行できる
        notifier.send("ユーザー登録完了");
    }
}

このように設計しておけば、「メール通知からLINE通知に切り替えたい」という場合でも、UserManager のコードを一切修正する必要がありません。渡す実装クラスを変えるだけで済むからです。

この「変更に強い性質」こそが、実務でインターフェースが重宝される最大の理由です。

参考リンク:Spring Framework Documentation (IoC Container)

Java 8以降のdefaultメソッドについて

さらに、近年のJava開発では知っておくべき機能があります。Java 8から導入されたdefaultメソッドです。

以前のインターフェースは「実装を持つことができない」のが常識でしたが、defaultキーワードを使うことで、インターフェース内に初期実装を持てるようになりました。

public interface Logger {
    void log(String msg);

    // 共通の実装を提供できる
    default void logError(String msg) {
        log("ERROR: " + msg);
    }
}

これにより、既存のインターフェースに新しいメソッドを追加しても、実装クラス側でコンパイルエラーにならずに済むようになり、ライブラリの互換性維持が容易になりました。

まとめ:インターフェースは変更に強いコードの鍵

本記事では、Javaの implements の仕組みと、実務での活用ポイントを解説しました。

  • 契約の定義:メソッドの実装を強制し、クラスの規格を統一する
  • 多重実装:複数の役割を1つのクラスに持たせることができる
  • 疎結合の実現:DIと組み合わせることで、変更やテストに強い設計になる

最初は「コード量が増えるだけでは?」と感じるかもしれませんが、規模が大きくなるにつれて、インターフェースによる設計の恩恵を強く感じるはずです。まずは小さなプログラムで、クラスを直接使うのではなくインターフェース経由で操作する書き方を練習してみてください。

さらに、実務レベルのJava設計やDIの仕組みを深く理解したい場合は、プロのエンジニアによるコードレビューを受けながら学習を進めるのが近道です。

つまずいたら、現役エンジニアと一緒に解決しよう

この記事で扱った【Java】は、独学だと細部で詰まりやすい分野です。さらに理解を深めたい方は、Zerocode Onlineで実務直結の学習を進めてみませんか。

現役エンジニア1on1

コード添削・詰まり解消を丁寧にサポート。

実務設計まで網羅

Java/SQL/Spring Bootを体系的に習得。

ポートフォリオ支援

現場で刺さる成果物づくりを伴走。

完全オンライン

時間と場所を選ばず学べます。

Join us! 未経験からエンジニアに挑戦できる環境で自分の可能性を信じてみよう 採用ページを見る→

記事監修

ドライブライン編集部

[ この記事をシェアする ]

記事一覧へ戻る