JAVA練習問題4-4:クラスの継承と抽象クラスを理解しよう

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

JAVAの初心者向け問題4-4:クラスの継承と抽象クラスを理解しよう

この問題を解くために必要な知識:
【レベル1~3の知識】
コメントの書き方、変数と定数、基本データ型とプリミティブ型、四則演算と論理演算、入力と出力(Scannerクラス)、配列、分岐処理(if、if~else、switch)、繰り返し処理(for、while、do~while)、メソッドの定義と呼び出し、メソッドの戻り値、メソッドのオーバーロード、例外処理(try-catch文、throws、throw)、クラスの定義と使用、インスタンス、コンストラクタ、コレクションの基礎、コレクション(List, ArrayList)、コレクション(HashSet, TreeSet)、コレクション(HashMap, TreeMap)

【レベル4の知識】
ゲッターとセッター、カプセル化、クラスメンバ、インスタンスメソッド、クラスの継承、抽象クラス、インターフェース

<<前の問題 問題集Top 次の問題>>

JAVAの文法「クラスの継承と抽象クラス」とは

ここではクラスの継承と抽象クラスの意味や使い方を復習します。必要ない方はここをクリックして練習問題へ飛びましょう。



クラス継承とは?

クラス継承は、既存のクラス(親クラス、またはスーパークラス)から新しいクラス(子クラス、またはサブクラス)を作成する機能です。

親クラスのフィールドやメソッドを子クラスが引き継ぐことができ、同じコードを繰り返し書く手間を省けます。

例えば、動物を表すAnimalクラスを親クラスにし、そのクラスを継承したDogCatクラスを作成することができます。

継承により、DogCatAnimalが持つ共通の機能をそのまま使用できます。

// 親クラス
class Animal {
    void eat() {
        System.out.println("食べる");
    }
}

// 子クラス
class Dog extends Animal {
    void bark() {
        System.out.println("吠える");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();  // 親クラスのメソッドを継承
        dog.bark(); // 子クラス固有のメソッド
    }
}

上記の例では、DogクラスがAnimalクラスを継承しています。

これにより、DogクラスはAnimalクラスのeat()メソッドを利用でき、さらにbark()という独自の機能を追加しています。

抽象クラスとは?

抽象クラスは、完全に定義されていないメソッド(抽象メソッド)を含むクラスです。

抽象クラスは、具体的な実装を持つことはできませんが、継承されることで具体的なクラスにその実装を求めます。

抽象クラスは、通常、他のクラスに共通の機能を提供しつつ、具体的な実装をサブクラスに委ねたい場合に使います。

抽象クラスにはabstractキーワードを使い、抽象メソッドを含めることができます。

// 抽象クラス
abstract class Animal {
    // 抽象メソッド
    abstract void makeSound();
    
    // 具体的なメソッド
    void eat() {
        System.out.println("食べる");
    }
}

// サブクラスで抽象メソッドを実装
class Dog extends Animal {
    void makeSound() {
        System.out.println("ワンワン");
    }
}

class Cat extends Animal {
    void makeSound() {
        System.out.println("ニャーニャー");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog();
        Animal cat = new Cat();
        dog.makeSound(); // ワンワン
        cat.makeSound(); // ニャーニャー
    }
}

この例では、Animalという抽象クラスがmakeSound()という抽象メソッドを持っています。DogCatAnimalを継承し、それぞれ独自にmakeSound()メソッドを実装しています。

これにより、Dogは「ワンワン」、Catは「ニャーニャー」と異なる音を出すことができるようになっています。

継承と抽象クラスの使いどころ

  • 継承は、コードの再利用や共通の機能をまとめたい場合に便利です。多くのクラスが同じ機能を持つ場合、親クラスにその機能を定義し、子クラスで利用することでコードの重複を避けられます。
  • 抽象クラスは、同じ「型」や「構造」を持つが、具象的な実装が異なるクラスを作りたいときに使います。具体的な実装は子クラスに任せつつ、共通の処理は親クラスで提供できます。

まとめ

Javaにおける「クラス継承」と「抽象クラス」は、オブジェクト指向プログラミングの基本であり、コードの再利用性と保守性を高めるための重要な技術です。

継承を活用することで、重複コードを削減し、抽象クラスを使って共通の構造を提供しつつ、個別の実装を柔軟にすることが可能です。




JAVA練習問題4-4_クラスの継承と抽象クラスを使った動物管理プログラムを作ろう

動物の情報を管理するプログラムを作成しましょう。

このプログラムでは、抽象クラスを使用して複数の動物の情報を管理します。

この問題の要件

以下の要件に従ってプログラムを作成して下さい。

  • Animalという抽象クラスを作成し、以下のメソッドを宣言すること:
    • makeSound(): void – 動物の鳴き声を出力する抽象メソッド
    • getName(): String – 動物の名前を取得する抽象メソッド
  • Animal抽象クラスを継承する以下のクラスを作成すること:
    • Dogクラス: 名前(name)を持つ犬。鳴き声は「ワンワン」である。
    • Catクラス: 名前(name)を持つ猫。鳴き声は「ニャーニャー」である。
  • 各クラスのコンストラクタは必要な値(名前)を受け取り、対応するフィールドに設定すること。
  • Mainクラスを作成し、ユーザーから動物の情報を入力して鳴き声を出力するプログラムを実装すること。

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

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

犬の名前を入力してください: ポチ
犬の名前: ポチ
ワンワン
猫の名前を入力してください: ミケ
猫の名前: ミケ
ニャーニャー

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

この問題を解くヒント

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

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

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

1.import文
 1-1. Scannerクラスのインポート
2.Animal抽象クラスの定義
 2-1. フィールドnameの定義
 2-2. コンストラクタの定義(nameを受け取る)
 2-3. 抽象メソッドmakeSoundの宣言
 2-4. 抽象メソッドgetNameの宣言
3.Dogクラスの定義
 3-1. Animal抽象クラスを継承
 3-2. コンストラクタの定義(nameを受け取る)
 3-3. makeSoundメソッドの実装(”ワンワン”を出力)
 3-4. getNameメソッドの実装(nameを返す)
4.Catクラスの定義
 4-1. Animal抽象クラスを継承
 4-2. コンストラクタの定義(nameを受け取る)
 4-3. makeSoundメソッドの実装(”ニャーニャー”を出力)
 4-4. getNameメソッドの実装(nameを返す)
5.Mainクラスの定義
 5-1. mainメソッド
  5-1-1. Scannerオブジェクトの作成
  5-1-2. ユーザーに犬の名前を入力させる
  5-1-3. Dogオブジェクトの作成と名前の表示
  5-1-4. DogオブジェクトのmakeSoundメソッドの呼び出し
  5-1-5. ユーザーに猫の名前を入力させる
  5-1-6. Catオブジェクトの作成と名前の表示
  5-1-7. CatオブジェクトのmakeSoundメソッドの呼び出し
  5-1-8. Scannerオブジェクトを閉じる

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

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

import java.util.Scanner;

// 抽象クラスAnimalの定義
abstract class Animal {
    protected String name;

    // コンストラクタ。名前を受け取る
    public Animal(String name) {
        ***ここにコンストラクタのコードを書いてください***
    }

    // 抽象メソッドの宣言
    public abstract void makeSound();
    public abstract String getName();
}

// Dogクラスの定義。Animal抽象クラスを継承する
class Dog extends Animal {

    // コンストラクタ。名前を受け取る
    public Dog(String name) {
        ***ここにコンストラクタのコードを書いてください***
    }

    // 抽象メソッドmakeSoundの実装
    @Override
    public void makeSound() {
        ***ここに犬の鳴き声を出力するコードを書いてください***
    }

    // 抽象メソッドgetNameの実装
    @Override
    public String getName() {
        ***ここに名前を返すコードを書いてください***
    }
}

// Catクラスの定義。Animal抽象クラスを継承する
class Cat extends Animal {

    // コンストラクタ。名前を受け取る
    public Cat(String name) {
        ***ここにコンストラクタのコードを書いてください***
    }

    // 抽象メソッドmakeSoundの実装
    @Override
    public void makeSound() {
        ***ここに猫の鳴き声を出力するコードを書いてください***
    }

    // 抽象メソッドgetNameの実装
    @Override
    public String getName() {
        ***ここに名前を返すコードを書いてください***
    }
}

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

        // ユーザーに犬の名前を入力させる
        System.out.print("犬の名前を入力してください: ");
        String dogName = scanner.nextLine();
        Dog dog = new Dog(dogName);
        System.out.println("犬の名前: " + dog.getName());
        dog.makeSound();

        // ユーザーに猫の名前を入力させる
        System.out.print("猫の名前を入力してください: ");
        String catName = scanner.nextLine();
        Cat cat = new Cat(catName);
        System.out.println("猫の名前: " + cat.getName());
        cat.makeSound();

        scanner.close();
    }
}

 

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

解答例

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

正解コードの例

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

********************

import java.util.Scanner;

// 抽象クラスAnimalの定義
abstract class Animal {
    protected String name;

    // コンストラクタ。名前を受け取る
    public Animal(String name) {
        this.name = name;
    }

    // 抽象メソッドの宣言
    public abstract void makeSound();
    public abstract String getName();
}

// Dogクラスの定義。Animal抽象クラスを継承する
class Dog extends Animal {

    // コンストラクタ。名前を受け取る
    public Dog(String name) {
        super(name);
    }

    // 抽象メソッドmakeSoundの実装
    @Override
    public void makeSound() {
        System.out.println("ワンワン");
    }

    // 抽象メソッドgetNameの実装
    @Override
    public String getName() {
        return name;
    }
}

// Catクラスの定義。Animal抽象クラスを継承する
class Cat extends Animal {

    // コンストラクタ。名前を受け取る
    public Cat(String name) {
        super(name);
    }

    // 抽象メソッドmakeSoundの実装
    @Override
    public void makeSound() {
        System.out.println("ニャーニャー");
    }

    // 抽象メソッドgetNameの実装
    @Override
    public String getName() {
        return name;
    }
}

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

        // ユーザーに犬の名前を入力させる
        System.out.print("犬の名前を入力してください: ");
        String dogName = scanner.nextLine();
        Dog dog = new Dog(dogName);
        System.out.println("犬の名前: " + dog.getName());
        dog.makeSound();

        // ユーザーに猫の名前を入力させる
        System.out.print("猫の名前を入力してください: ");
        String catName = scanner.nextLine();
        Cat cat = new Cat(catName);
        System.out.println("猫の名前: " + cat.getName());
        cat.makeSound();

        scanner.close();
    }
}

********************

コードの解説

今回のコードでは、Javaの「クラス継承」と「抽象クラス」の概念を学ぶことができます。

以下にブロックごとに解説していきます。

抽象クラスAnimalの定義

abstract class Animal {
    protected String name;
    public Animal(String name) {
        this.name = name;
    }
    public abstract void makeSound();
    public abstract String getName();
}

ここでは、Animalという抽象クラスが定義されています。抽象クラスとは、完全には実装されていないクラスのことです。

このクラスには、makeSound()getName()という抽象メソッドが宣言されていますが、具体的な処理内容は記述されていません。

抽象メソッドは、子クラスで具体的に実装する必要があります。

また、nameというフィールド(変数)はprotectedで定義されており、このクラスを継承したクラスからアクセスできるようにしています。

Dogクラスの定義

class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
    @Override
    public void makeSound() {
        System.out.println("ワンワン");
    }
    @Override
    public String getName() {
        return name;
    }
}

Dogクラスは、Animalクラスを継承しており、makeSound()getName()の抽象メソッドをオーバーライドしています。

Dogクラスの中では、makeSound()メソッドで「ワンワン」と出力する具体的な処理を実装しています。

super(name)は、親クラスであるAnimalクラスのコンストラクタを呼び出して、nameを初期化しています。

Catクラスの定義

class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }
    @Override
    public void makeSound() {
        System.out.println("ニャーニャー");
    }
    @Override
    public String getName() {
        return name;
    }
}

CatクラスもAnimalクラスを継承しており、同様にmakeSound()メソッドとgetName()メソッドをオーバーライドしています。

こちらでは「ニャーニャー」と出力する処理が実装されています。

メインメソッドとユーザー入力

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

        System.out.print("犬の名前を入力してください: ");
        String dogName = scanner.nextLine();
        Dog dog = new Dog(dogName);
        System.out.println("犬の名前: " + dog.getName());
        dog.makeSound();

        System.out.print("猫の名前を入力してください: ");
        String catName = scanner.nextLine();
        Cat cat = new Cat(catName);
        System.out.println("猫の名前: " + cat.getName());
        cat.makeSound();

        scanner.close();
    }
}

メインメソッドでは、ユーザーから犬と猫の名前を入力してもらい、それぞれの名前をDogCatオブジェクトに渡しています。

dog.makeSound()cat.makeSound()を呼び出すと、各クラスでオーバーライドされたmakeSound()メソッドが実行され、犬は「ワンワン」、猫は「ニャーニャー」と鳴く動作が行われます。

まとめ

このコードでは、クラス継承抽象クラスを通じて、親クラスから共通の機能を継承しつつ、各サブクラスで独自の動作を定義する方法を学びました。

継承を活用することで、コードの再利用性を高めることができ、抽象クラスによってサブクラスに特定の実装を強制することが可能です。

<<前の問題 問題集Top 次の問題>>

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

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

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






    JAVA練習問題集へ戻る
    トップページへ戻る