【JAVA】レッスン5-07:抽象クラスを理解しよう

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

この記事で学べる知識:抽象クラス

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

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

JAVAの「抽象クラス」とは

この章ではJAVAにおける「抽象クラス」の意味や使い方を学習します。必要ない方はここをクリックして練習問題へ飛びましょう。

Javaのプログラミングにおいて、「抽象クラス」はオブジェクト指向の概念の一つです。

複数のクラスで共通の機能を持たせたいときに、抽象クラスを利用することでコードの再利用性を高めることができます。

本節では抽象クラスの定義方法とその基本的な使い方について学びましょう。

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

抽象クラスとは?

抽象クラスは「インスタンス生成できないクラス」であり、他の子クラスに継承されることを前提としています。

通常のクラスと同様に変数やメソッドを持つことができますが、特定のメソッドにおいて実装を持たない「抽象メソッド」を含めることができる点が特徴です。

抽象クラスを使うことで共通の基盤を提供し、複数の子クラスでの個別の実装を促すことができます。

抽象クラスの基本構文

抽象クラスと抽象メソッドの定義は、以下のように行います。

抽象クラスは abstract キーワードを用いて宣言し、抽象メソッドも同様に abstract キーワードを使って定義します。

// 抽象クラスの例
abstract class Animal {
    // 抽象メソッド(具体的な実装を持たない)
    abstract void sound();
    
    // 通常のメソッド(実装を持つ)
    void sleep() {
        System.out.println("Sleeping...");
    }
}

上記の例ではAnimal クラスは抽象クラスであり、sound() メソッドが抽象メソッドとして定義されています。

sound() メソッドはAnimal クラスを継承した子クラスで実装されることを期待しています。

抽象クラスの使用例

抽象クラスを使うと共通の動作を持ちながらも、具体的な部分を子クラスで自由に定義できます。

次にDogCat という2つのクラスが Animal クラスを継承し、各クラスで異なる sound() メソッドを実装する例を見てみましょう。

// 抽象クラスの定義
abstract class Animal {
    abstract void sound();
    
    void sleep() {
        System.out.println("Sleeping...");
    }
}

// DogクラスがAnimalクラスを継承
class Dog extends Animal {
    void sound() {
        System.out.println("Bark");
    }
}

// CatクラスがAnimalクラスを継承
class Cat extends Animal {
    void sound() {
        System.out.println("Meow");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog();
        Animal myCat = new Cat();
        
        myDog.sound();  // 出力: Bark
        myCat.sound();  // 出力: Meow
        myDog.sleep();  // 出力: Sleeping...
    }
}

この例ではDog クラスと Cat クラスが Animal クラスを継承し、それぞれのクラスで sound() メソッドを独自に実装しています。

Main クラスの main メソッド内で myDogmyCat をそれぞれインスタンス化して sound() を呼び出すと、各クラスの実装に従った出力が得られます。

またsleep() メソッドは Animal クラスで既に実装されているため、子クラスで再定義する必要がありません。

抽象クラスを使うメリット

抽象クラスを使う主なメリットは、共通の基盤を提供しつつ子クラスに実装を委ねることができる点です。

これにより各クラスの実装をカスタマイズしやすくなり、コードの可読性とメンテナンス性が向上します。

また抽象クラスを利用することで、設計時に共通のインターフェースや動作を規定でき、後から拡張しやすい柔軟なコードを書くことができます。

まとめ

抽象クラスはJavaでのオブジェクト指向設計において重要な役割を担う概念です。

共通の動作や構造を定義しつつ、具体的な実装は子クラスで行うため、継承関係を活かした柔軟なプログラムが実現できます。

これで抽象クラスの基本が理解できたでしょうか?

次の練習問題で実際にコードを書きながらさらに理解を深めていきましょう!

練習問題5-7:抽象クラスの仕組みを学ぼう

動物の種類によって異なる鳴き声を表示するプログラムを作成しましょう。

このプログラムでは動物の基本的なクラスとして抽象クラスを使い、それぞれの動物(犬と猫)に特有の鳴き声を実装します。

また共通の動作としてすべての動物が「寝ている」という動作も表示させましょう。

この問題の要件

以下の要件に従ってコードを完成させてください。

  1. 抽象クラス Animal を定義し、以下の内容を持たせること。
    • makeSound() という抽象メソッドを宣言すること(戻り値は void)。
    • sleep() という具象メソッドを実装し、「動物は寝ています…」と表示すること。
  2. Animal クラスを継承する Dog クラスを定義し、以下を実装すること。
    • makeSound() メソッドで「ワンワン!」と出力すること。
  3. Animal クラスを継承する Cat クラスを定義し、以下を実装すること。
    • makeSound() メソッドで「ニャーニャー!」と出力すること。
  4. Main クラスの main メソッドで、以下を実行すること。
    • Dog クラスのインスタンスを生成し、その makeSound() メソッドと sleep() メソッドを呼び出すこと。
    • Cat クラスのインスタンスを生成し、その makeSound() メソッドと sleep() メソッドを呼び出すこと。

ただし、以下のような実行結果となるコードを書くこと。

*****↓↓正解コードの実行結果の例↓↓*****

ワンワン!
ニャーニャー!
動物は寝ています...
動物は寝ています...

この問題を解くヒント

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

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

正解のコードは上から順に以下のような構成となっています。
(※下記の□はコード内のインデントを表しています)

1:抽象クラスAnimalの定義
  □ 抽象メソッドmakeSoundの宣言
  □ 具象メソッドsleepの定義
    □ 「動物は寝ています…」と出力

2:Dogクラスの定義
  □ Animalクラスを継承
  □ makeSoundメソッドをオーバーライドし、「ワンワン!」と出力

3:Catクラスの定義
  □ Animalクラスを継承
  □ makeSoundメソッドをオーバーライドし、「ニャーニャー!」と出力

4:Mainクラスの定義
  □ mainメソッドの定義
  □ □ Dogクラスのインスタンスを生成し、変数dogに代入
  □ □ Catクラスのインスタンスを生成し、変数catに代入
  □ □ dogのmakeSoundメソッドを呼び出し、鳴き声を出力
  □ □ catのmakeSoundメソッドを呼び出し、鳴き声を出力
  □ □ dogのsleepメソッドを呼び出し、「動物は寝ています…」を出力
  □ □ catのsleepメソッドを呼び出し、「動物は寝ています…」を出力

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

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

// 動物の種類を表す抽象クラス
abstract class Animal {
    /*【穴埋め問題1】
    ここに抽象メソッドmakeSoundを宣言してください。
    */

    // 共通の動作を定義するメソッド
    public void sleep() {
        System.out.println("動物は寝ています...");
    }
}

// 犬のクラス (Animalクラスを継承して実装)
class Dog extends Animal {
    /*【穴埋め問題2】
    ここにmakeSoundメソッドをオーバーライドし、「ワンワン!」と出力するコードを書いてください。
    */
}

// 猫のクラス (Animalクラスを継承して実装)
class Cat extends Animal {
    /*【穴埋め問題3】
    ここにmakeSoundメソッドをオーバーライドし、「ニャーニャー!」と出力するコードを書いてください。
    */
}

public class Main {
    public static void main(String[] args) {
        // DogとCatのインスタンスを作成し、動作を確認する
        Animal dog = new Dog();  // DogはAnimalのサブクラス
        Animal cat = new Cat();  // CatはAnimalのサブクラス

        // 各動物の鳴き声を出す (抽象メソッドの実装部分が呼び出される)
        dog.makeSound();
        cat.makeSound();

        // sleepメソッドはAnimalクラスで実装されているので、直接使用できる
        dog.sleep();
        cat.sleep();
    }
}

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

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



解答例と解説

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

正解コードの例

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

// 動物の種類を表す抽象クラス
abstract class Animal {
    // 抽象メソッド: 具体的な動物クラスで実装する必要がある
    public abstract void makeSound();

    // 共通の動作を定義するメソッド
    public void sleep() {
        System.out.println("動物は寝ています...");
    }
}

// 犬のクラス (Animalクラスを継承して実装)
class Dog extends Animal {
    // 抽象メソッドを具体的に実装する
    @Override
    public void makeSound() {
        System.out.println("ワンワン!");
    }
}

// 猫のクラス (Animalクラスを継承して実装)
class Cat extends Animal {
    // 抽象メソッドを具体的に実装する
    @Override
    public void makeSound() {
        System.out.println("ニャーニャー!");
    }
}

public class Main {
    public static void main(String[] args) {
        // DogとCatのインスタンスを作成し、動作を確認する
        Animal dog = new Dog();  // DogはAnimalのサブクラス
        Animal cat = new Cat();  // CatはAnimalのサブクラス

        // 各動物の鳴き声を出す (抽象メソッドの実装部分が呼び出される)
        dog.makeSound();
        cat.makeSound();

        // sleepメソッドはAnimalクラスで実装されているので、直接使用できる
        dog.sleep();
        cat.sleep();
    }
}

正解コードの解説

このコードではJavaの「抽象クラス」を使用し、異なる動物が特定の動作(鳴き声)を持つように設定しています。

各クラスやメソッドの役割を詳しく見ていきましょう。

抽象クラスと抽象メソッド

abstract class Animal {
    public abstract void makeSound();

    public void sleep() {
        System.out.println("動物は寝ています...");
    }
}
  • 抽象クラス(abstract class Animal
    抽象クラス Animal は「動物」を表す基本クラスであり、特定の動作を子クラスで実装するための基盤です。abstract キーワードによりこのクラスは直接インスタンス化できず、他のクラスが継承するためだけに存在します。
  • 抽象メソッド(public abstract void makeSound();
    makeSound は抽象メソッドです。抽象メソッドは具体的な処理を持たず、子クラスで必ず実装されなければなりません。このメソッドを通して動物ごとに異なる鳴き声を定義できます。
  • 具象メソッド(public void sleep()
    sleep メソッドは具体的な処理を持つメソッドで、すべての動物が同じ動作(「寝ています…」のメッセージ出力)を行います。抽象クラス内に具象メソッドを定義することで共通の動作を各子クラスに引き継げます。

犬のクラスの定義

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("ワンワン!");
    }
}
  • 継承(class Dog extends Animal
    Dog クラスは Animal クラスを継承しているため、Animal クラスのすべてのメソッドやプロパティを利用できます。ここでは makeSound メソッドを具体的に実装する必要があるため@Override アノテーションを使用します。
  • メソッドのオーバーライド
    makeSound メソッドをオーバーライドして犬の鳴き声「ワンワン!」を出力するようにしています。これにより、犬特有の動作を表現できます。

猫のクラスの定義

class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("ニャーニャー!");
    }
}
  • 継承とメソッドのオーバーライド
    Cat クラスも Animal クラスを継承しており、makeSound メソッドをオーバーライドして猫の鳴き声「ニャーニャー!」を出力します。これにより、異なる動物がそれぞれの鳴き声を持つことができます。

Mainクラスとメインメソッド

  • インスタンス化とポリモーフィズム
    Animal 型の変数 dogDog クラスのインスタンスを、catCat クラスのインスタンスを代入しています。Animal 型を通して異なるクラスのオブジェクトを扱うことで、ポリモーフィズムを活用しています。これにより、makeSound メソッドは dog では「ワンワン!」、cat では「ニャーニャー!」と異なる動作を行います。
  • メソッドの呼び出し
    makeSound メソッドを呼び出すと、それぞれの鳴き声が出力されます。また、sleep メソッドは Animal クラスで定義されているため、すべての Animal クラスを継承したインスタンスが同じ「動物は寝ています…」のメッセージを表示します。

まとめ

このコードを通じてJavaの「抽象クラス」や「抽象メソッド」の概念を学びました。

抽象クラスは特定の機能を実装しないまま共通の構造を提供し、子クラスに具体的な動作を割り当てるために使われます。

抽象クラスを使うと異なる動物がそれぞれの特性を持つ柔軟なプログラムを実現できます。

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

この記事への質問・コメント

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

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






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