【JAVA】レッスン5-08:インターフェースを理解しよう

記事内に商品プロモーションを含む場合があります

この記事で学べる知識:インターフェース

この記事の練習問題で使用する知識:
基礎構文、制御構造、メソッド、コレクション(レッスン1~4)クラスの定義と使用コンストラクタカプセル化クラスメンバとインスタンスメンバクラスの継承メソッドのオーバーライド抽象クラスインターフェース

<<前のページ JAVA Topへ 次のページ>>

JAVAの文法「インターフェース」とは

ここではインターフェースの意味や使い方を学習します。必要ない方はここをクリックして練習問題へ飛びましょう。

Javaにはクラスの設計に関する重要な要素として「インターフェース」という仕組みがあります。

インターフェースはクラス間で共通の機能を定義し、コードの柔軟性や再利用性を高めるために用いられます。

ここではインターフェースの基本的な使い方や抽象クラスとの違いについて学び、実際の利用方法を見ていきましょう。

【初心者向け】Javaのオブジェクト指向を分かりやすくまとめた概念図。 特にクラスの継承、オーバーライド、抽象クラス、インターフェース、インスタンス生成の関係性を視覚的に理解できるようまとめている。

インターフェースとは?

インターフェースはクラスが実装するための「契約」のようなものです。

インターフェースの中ではメソッドの宣言のみが行われ、具体的な処理は何も書きません。これにより複数のクラスが共通の名前のメソッドを持つことができ、それぞれのクラスが独自にメソッドを実装することができます。

interface インターフェース名 { //インターフェースの定義
    void メソッド名(); //メソッドの名前のみ定義
}

たとえば「動物」クラスと「乗り物」クラスに「移動」メソッドが共通して必要な場合、インターフェースを使って「移動」というメソッドの枠組みを定義し、各クラスで具体的な動作を記述できます。

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

Javaにはインターフェースと似た概念として「抽象クラス」がありますが、これらにはいくつかの重要な違いがあります。

  • 多重継承:Javaのクラスは1つの抽象クラスしか継承できませんが、複数のインターフェースを実装することが可能です。これにより複数の役割や特性を持つクラスを作成することができます。
  • 実装内容の有無:抽象クラスは一部のメソッドに具体的な実装を含めることができますが、インターフェースではメソッドの宣言のみが含まれます(Java 8以降、デフォルトメソッドやstaticメソッドに限りインターフェースでも実装が可能です)。
  • 適用範囲:抽象クラスは「〇〇の一種」という概念に適用され、クラスの基本構造や共通の属性を定義します。一方インターフェースは「〇〇ができる」という動作の契約をクラスに持たせるために使用されます。

インターフェースの定義方法

インターフェースの定義はinterfaceキーワードを使って行います。

次のコード例は「Playable」というインターフェースを定義したものです。

interface Playable {
    void play();
    void stop();
}

ここではplaystopという2つのメソッドを定義していますが、実装内容は含まれていません。

このインターフェースを実装するクラスは、それぞれのメソッドを具体的に実装する必要があります。

インターフェースの実装

インターフェースの実装はimplementsキーワードを使って行います。複数のインターフェースを同時に実装することも可能です。

次のコード例は「Playable」インターフェースを実装した「MusicPlayer」クラスを示しています。

class MusicPlayer implements Playable {
    @Override
    public void play() {
        System.out.println("音楽を再生します");
    }
    
    @Override
    public void stop() {
        System.out.println("音楽を停止します");
    }
}

このようにMusicPlayerクラスはPlayableインターフェースを実装し、playstopメソッドに具体的な処理を記述しています。

また複数のインターフェースを実装する場合は次のように記述します。

class VideoPlayer implements Playable, Recordable {
    // Playableインターフェースの実装
    @Override
    public void play() {
        System.out.println("ビデオを再生します");
    }
    
    @Override
    public void stop() {
        System.out.println("ビデオを停止します");
    }
    
    // Recordableインターフェースの実装
    @Override
    public void record() {
        System.out.println("録画を開始します");
    }
}

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

インターフェースの利点を活かした例を見てみましょう。

例えばゲームのキャラクターが「攻撃する」機能と「防御する」機能を持つ場合、これらをインターフェースとして定義すると、それぞれのキャラクターで異なる「攻撃」や「防御」の方法を実装できます。

interface Attackable {
    void attack();
}

interface Defendable {
    void defend();
}

class Warrior implements Attackable, Defendable {
    @Override
    public void attack() {
        System.out.println("剣で攻撃します");
    }
    
    @Override
    public void defend() {
        System.out.println("盾で防御します");
    }
}

class Mage implements Attackable, Defendable {
    @Override
    public void attack() {
        System.out.println("魔法で攻撃します");
    }
    
    @Override
    public void defend() {
        System.out.println("バリアを張ります");
    }
}

この例ではWarriorMageという2つのクラスが、AttackableDefendableインターフェースを実装しています。こ

れによりキャラクターごとに異なる攻撃や防御の方法を持たせることができ、インターフェースを利用することで柔軟な設計が可能です。

まとめ

インターフェースはJavaにおけるクラス間の共通の動作を定義するための仕組みで、抽象クラスとは異なり複数のインターフェースを同時に実装できるため、多様な機能を持たせる際に便利です。

これによりコードの再利用性や拡張性を高め、異なるクラス間で一貫性のある動作を提供できます。

JAVA練習問題4-5_インターフェースを使った図形の面積計算プログラム

インターフェースを使って複数の図形の面積を計算するプログラムを作成しましょう。

この問題の要件

以下の要件に従って作成して下さい。

  1. Shapeというインターフェースを作成し、以下のメソッドを宣言すること:
    • calculateArea(): double – 図形の面積を計算する
  2. Shapeインターフェースを実装する以下のクラスを作成すること:
    • Rectangleクラス: 幅(width)と高さ(height)を持つ長方形。面積は幅×高さで計算する。
    • Circleクラス: 半径(radius)を持つ円。面積はπ×半径×半径で計算する。
  3. 各クラスのコンストラクタは必要な値を受け取り、対応するフィールドに設定すること。
  4. Mainクラスを作成し、ユーザーから図形の情報を入力して面積を計算・表示するプログラムを実装すること。

ただし、以下のような実行結果となること。

----- ↓出力される結果の例↓ -----

長方形の幅を入力してください: 5
長方形の高さを入力してください: 10
長方形の面積: 50.0
円の半径を入力してください: 3
円の面積: 28.274333882308138

この問題を解くヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。

1:Scannerクラスをインポート
2:Shapeインターフェースの定義
  □ calculateAreaメソッドの定義
3:Rectangleクラスの定義とShapeインターフェースの実装
  □ widthフィールドをprivateで定義
  □ heightフィールドをprivateで定義
  □ Rectangleクラスのコンストラクタで幅と高さを受け取る
  □ calculateAreaメソッドのオーバーライド
    □ 幅と高さを掛けて面積を返す
4:Circleクラスの定義とShapeインターフェースの実装
  □ radiusフィールドをprivateで定義
  □ Circleクラスのコンストラクタで半径を受け取る
  □ calculateAreaメソッドのオーバーライド
    □ 円の面積を計算し返す
5:Mainクラスの定義
  □ mainメソッドの定義
  □ □ Scannerオブジェクトscannerの初期化
  □ □ 「長方形の幅を入力してください: 」と出力
  □ □ ユーザーから長方形の幅を入力し、widthに代入
  □ □ 「長方形の高さを入力してください: 」と出力
  □ □ ユーザーから長方形の高さを入力し、heightに代入
  □ □ Rectangleオブジェクトを作成し、長方形の面積を計算
  □ □ 「長方形の面積: 」と計算結果を出力
  □ □ 「円の半径を入力してください: 」と出力
  □ □ ユーザーから円の半径を入力し、radiusに代入
  □ □ Circleオブジェクトを作成し、円の面積を計算
  □ □ 「円の面積: 」と計算結果を出力

ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

import java.util.Scanner;

// Shapeインターフェースの定義
/* 【穴埋め問題1】
ここにShapeインターフェースを定義し、calculateAreaメソッドを宣言してください。
*/

// Rectangleクラスの定義。Shapeインターフェースを実装する
class Rectangle /* 【穴埋め問題2】ここにShapeインターフェースを実装するコードを記述してください。 */ {
    private double width;
    private double height;

    // コンストラクタ。幅と高さを受け取る
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    // インターフェースのcalculateAreaメソッドを実装
    /* 【穴埋め問題3】
    ここにインターフェースのcalculateAreaメソッドをオーバーライドして、長方形の面積を計算するコードを書いてください。
    */
}

// Circleクラスの定義。Shapeインターフェースを実装する
class Circle /* 【穴埋め問題4】ここにShapeインターフェースを実装するコードを記述してください。 */ {
    private double radius;

    // コンストラクタ。半径を受け取る
    public Circle(double radius) {
        this.radius = radius;
    }

    // インターフェースのcalculateAreaメソッドを実装
    /* 【穴埋め問題5】
    ここにインターフェースのcalculateAreaメソッドをオーバーライドして、円の面積を計算するコードを書いてください。
    */
}

// Mainクラスの定義。メインメソッドを含む
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // ユーザーに長方形の幅と高さを入力させる
        System.out.print("長方形の幅を入力してください: ");
        double width = scanner.nextDouble();
        System.out.print("長方形の高さを入力してください: ");
        double height = scanner.nextDouble();

        // 長方形の面積を計算
        Shape rectangle = new Rectangle(width, height);
        System.out.println("長方形の面積: " + rectangle.calculateArea());

        // ユーザーに円の半径を入力させる
        System.out.print("円の半径を入力してください: ");
        double radius = scanner.nextDouble();

        // 円の面積を計算
        Shape circle = new Circle(radius);
        System.out.println("円の面積: " + circle.calculateArea());
    }
}

この問題の穴埋めコードは以上です。

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

解答例と解説

この問題の一つの正解例とそのコードの解説を以下に示します。

正解コードの例

例えば以下のようなプログラムが考えられます。

import java.util.Scanner;

// Shapeインターフェースの定義
interface Shape {
    double calculateArea();
}

// Rectangleクラスの定義。Shapeインターフェースを実装する
class Rectangle implements Shape {
    private double width;
    private double height;

    // コンストラクタ。幅と高さを受け取る
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    // インターフェースのcalculateAreaメソッドを実装
    @Override
    public double calculateArea() {
        return width * height;
    }
}

// Circleクラスの定義。Shapeインターフェースを実装する
class Circle implements Shape {
    private double radius;

    // コンストラクタ。半径を受け取る
    public Circle(double radius) {
        this.radius = radius;
    }

    // インターフェースのcalculateAreaメソッドを実装
    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}

// Mainクラスの定義。メインメソッドを含む
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // ユーザーに長方形の幅と高さを入力させる
        System.out.print("長方形の幅を入力してください: ");
        double width = scanner.nextDouble();
        System.out.print("長方形の高さを入力してください: ");
        double height = scanner.nextDouble();

        // 長方形の面積を計算
        Shape rectangle = new Rectangle(width, height);
        System.out.println("長方形の面積: " + rectangle.calculateArea());

        // ユーザーに円の半径を入力させる
        System.out.print("円の半径を入力してください: ");
        double radius = scanner.nextDouble();

        // 円の面積を計算
        Shape circle = new Circle(radius);
        System.out.println("円の面積: " + circle.calculateArea());
    }
}

正解コードの解説

インターフェースはクラスが実装するべきメソッドの契約を定め、異なるクラスに共通の機能を提供しながら、それぞれのクラスが独自の実装を行うことを可能にする仕組みです。

このコードをブロックごとに解説していきます。

インターフェースShapeの定義

interface Shape {
    double calculateArea();
}

まず、Shapeインターフェースが定義されています。

このインターフェースは、図形の面積を計算するためのcalculateArea()というメソッドの宣言を含んでいますが、具体的な実装は持っていません。

インターフェースは、クラスに対して「このメソッドを実装してください」と指示する役割を果たします。

Rectangleクラスの定義と実装

class Rectangle implements Shape {
    private double width;
    private double height;

    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public double calculateArea() {
        return width * height;
    }
}

RectangleクラスはShapeインターフェースを実装しています。

implementsキーワードを使うことで、Shapeインターフェースに定義されたメソッドcalculateArea()を具体的に実装しています。

長方形の面積は幅×高さで計算されます。

@Overrideアノテーションは、親のインターフェースからメソッドをオーバーライドしていることを明示しています。

Circleクラスの定義と実装

class Circle implements Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}

CircleクラスもShapeインターフェースを実装しており、こちらでは円の面積を計算するためのcalculateArea()メソッドが具体的に実装されています。

円の面積は公式に従い、Math.PI * radius * radiusで計算されます。

メインメソッドでの実行

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // ユーザーに長方形の幅と高さを入力させる
        System.out.print("長方形の幅を入力してください: ");
        double width = scanner.nextDouble();
        System.out.print("長方形の高さを入力してください: ");
        double height = scanner.nextDouble();

        // 長方形の面積を計算
        Shape rectangle = new Rectangle(width, height);
        System.out.println("長方形の面積: " + rectangle.calculateArea());

        // ユーザーに円の半径を入力させる
        System.out.print("円の半径を入力してください: ");
        double radius = scanner.nextDouble();

        // 円の面積を計算
        Shape circle = new Circle(radius);
        System.out.println("円の面積: " + circle.calculateArea());

        scanner.close();
    }
}

メインメソッドでは、ユーザーから長方形の幅と高さ、そして円の半径を入力させ、それに基づいてRectangleCircleオブジェクトが作成されます。

各オブジェクトのcalculateArea()メソッドを呼び出して、図形の面積を計算して結果を表示します。

まとめ

このコードでは、インターフェースを使うことで、異なるクラスに共通のメソッドcalculateArea()を実装しつつ、クラスごとに異なる実装を提供しています。

インターフェースは、異なるクラスが共通の動作を持ちながらも、それぞれに独自の動作をさせたい場合に非常に有効です。

<<前のページ JAVA Topへ 次のページ>>

この問題への質問・コメント

この問題を作成するにあたりAIを活用しています。

問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。






    JAVAテキスト&問題集へ戻る
    トップページへ戻る