Javaプログラミング練習問題(抽象化・多態性)

Java

こんにちは。ECF Tech
ブログ担当 Michiharu.Tです。

Javaプログラミング向け練習問題、オブジェクト指向プログラミング編。今回は抽象化・多態性がテーマです。多態性そのものを問題にする内容ではありませんが、動作確認のMainクラスでは、多態性を活かしたプログラムになっています。ぜひ普段の学習にお役立てください。

一般的なJavaの学習順序に沿ったテーマの一覧(※随時追加)は、こちらのリンクよりご確認頂けます。

Javaプログラミング

Javaのトピックスです。主に初心者向けにプログラミング学習ネタを提供していきます。

解説動画

2023/05/27 解説動画を掲載しました。

問題編

アクセス修飾子について:
各問題のメンバ変数、コンストラクタ、メソッド定義において特にことわりが無い場合、すべてpublicを指定してください。

Q001

問題

下の仕様に基づいて、各クラスを作成してください。
(仕様)
ゲームに登場するアイテムを表すItemクラスを抽象クラスとして作成します。次のメンバ変数、コンストラクタ、メソッドを作成し、Item.javaとして保存します。

  • メンバ変数の作成
    • 名前を表すnameをString型で宣言します。
    • 修正値を表すvalueをint型で宣言します。
  • コンストラクタの作成
    • 引数:
      • name:String型
      • value:int型
    • 処理内容:引数で与えられた値を、同名のメンバ変数に代入します。
  • useメソッドの作成(抽象メソッド)
    • 概要:アイテムを使った場合の処理を記述します。
    • 引数:なし
    • 戻り値:なし

武器を表すBukiクラスを、Itemクラスを継承して作成します。次のメンバ変数、コンストラクタ、メソッドを追加し、Buki.javaとして保存します。

  • コンストラクタの作成
    • 引数:
      • name:String型
      • value:int型
    • 処理内容:
      • 渡された2つの引数を用いて、親クラスのコンストラクタを呼び出します。
  • useメソッドの実装
    useメソッドをオーバーライドし、次のように処理をします。

    • 処理内容:
      • 「xxxxでこうげき!!」と表示します。(xxxxはメンバ変数nameの値が入ります)
      • 「敵にyyのダメージ!」と表示します。(yyはメンバ変数valueの値が入ります)

防具を表すArmorクラスを、Itemクラスを継承して作成します。次のメンバ変数、コンストラクタ、メソッドを追加し、Armor.javaとして保存します。

  • コンストラクタの作成
    • 引数:
      • name:String型
      • value:int型
    • 処理内容:
      • 渡された2つの引数を用いて、親クラスのコンストラクタを呼び出します。
  • useメソッドの実装
    useメソッドをオーバーライドし、次のように処理をします。

    • 処理内容:
      • 「xxxxを身に着けた」と表示します。(xxxxはメンバ変数nameの値が入ります)
      • 「守備力がyy上がった」と表示します。(yyはメンバ変数valueの値が入ります)

提供コード

下記のMain.javaを作成した他のソースファイルと同じフォルダ内に保存して動作確認し、実行結果が得られることを確認してください。

public class Main {
    public static void main(String[] args) {
        Item[] items = {
            new Buki("鉄の剣",20),
            new Armor("皮の服",10)
        };
        for (Item item : items) {
            item.use();
        }
    }
}

実行結果

鉄の剣でこうげき!!
敵に20のダメージ!
皮の服を身に着けた
守備力が10上がった

Q002

問題

下の仕様に基づいて、各クラス・インタフェースを作成してください。
(仕様)
「転送可能」という特徴を表すTransferableインタフェースを作成します。次の抽象メソッドを作成し、Transferable.javaとして保存します。

  • transferメソッドの作成(抽象メソッド)
    • 概要:データの転送処理を行ないます
    • 引数:なし
    • 戻り値:なし

スイッチ(通信機器)を表すSwitchクラスを、Transferableインタフェースを実装して作成します。次のメンバ変数、コンストラクタ、メソッドを追加し、Switch.javaとして保存します。

  • transferメソッドの実装
    • 処理内容:
      • 「MACアドレスを使ってデータを転送します」と表示します。

ルータ(通信機器)を表すRouterクラスを、Transferableインタフェースを実装して作成します。次のメンバ変数、コンストラクタ、メソッドを追加し、Router.javaとして保存します。

  • transferメソッドの実装
    • 処理内容:
      • 「IPアドレスを使ってデータを転送します」と表示します。

提供コード

下記のMain.javaを作成した他のソースファイルと同じフォルダ内に保存して動作確認し、実行結果が得られることを確認してください。

public class Main {
    public static void main(String[] args) {
        Transferable[] parts = {
            new Switch(),
            new Router()
        };

        for (Transferable work : parts) {
            work.transfer();
        }
    }
}

実行結果

MACアドレスを使ってデータを転送します
IPアドレスを使ってデータを転送します

Q003

問題

下の仕様に基づいて、各クラス・インタフェースを作成してください。
(仕様)
お店のクーポン券を表すCouponインタフェースを作成します。次の抽象メソッドを作成し、Coupon.javaとして保存します。

  • discountメソッドの作成(抽象メソッド)
    • 概要:引数で受け取った金額から一定の値下げを行ない、値下げの値を返します。
    • 引数:amount:int型
    • 戻り値:int型

割引クーポンを表すPercentageCouponクラスを、Couponインタフェースを実装して作成します。次のメンバ変数、コンストラクタ、メソッドを追加し、PercentageCoupon.javaとして保存します。

  • メンバ変数の作成
    • 割引率を表すrateをdouble型で定義します。
  • コンストラクタの作成
    • 引数:
      • rate:double型
    • 処理内容:引数で与えられた値を、同名のメンバ変数に代入します。
  • discountメソッドの実装
    • 処理内容:
      • メンバ変数rateの値に基づいて割引額を求め(小数点以下は切り捨て)、引数amountから割引額を引いた値を返します。

定額クーポンを表すFixedCouponクラスを、Couponインタフェースを実装して作成します。次のメンバ変数、コンストラクタ、メソッドを追加し、FixedCoupon.javaとして保存します。

  • メンバ変数の作成
    • 割引額を表すdiscountAmountをint型で定義します。
  • コンストラクタの作成
    • 引数:
      • discountAmount:int型
    • 処理内容:引数で与えられた値を、同名のメンバ変数に代入します。
  • discountメソッドの実装
    • 処理内容:
      • 引数amountの値からメンバ変数discountAmountの値を引き算した結果を返します。

レジを表すCasherクラスを作成します。次のクラスメソッドを作成し、Casher.javaとして保存します。

  • paymentメソッド(クラスメソッド)の作成
    • 概要:金額とクーポンの情報から、合計額を計算します
    • 引数:
      • amount:int型
      • coupon:Coupon型
    • 戻り値:int型
    • 処理内容:amountの値を引数として、couponのdiscountメソッドを呼び出します。discountメソッドの戻り値をそのまま返します。

提供コード

下記のMain.javaの①~④の記述に基づき、プログラムを追記します。他のソースファイルと同じフォルダ内に保存して動作確認し、実行結果が得られることを確認してください。

public class Main {
    public static void main(String[] args) {
        PercentageCoupon coupon1 = new PercentageCoupon(0.3);
        FixedCoupon coupon2 = new FixedCoupon(1000);
        System.out.println(Casher.payment(5000, coupon1));
        System.out.println(Casher.payment(5000, coupon2));

        //①変数coupon3を宣言します。5割引のクーポンを生成し代入します。
        //②変数coupon4を宣言します。1500円引のクーポンを生成し代入します。
        //③Casherのpaymentメソッドを呼び出し、5000円に対してcoupon3を適用した結果を表示します。
        //④Casherのpaymentメソッドを呼び出し、5000円に対してcoupon4を適用した結果を表示します。
    }    
}

実行結果

3500
4000
2500
3500

Q004

問題

下の仕様に基づいて、各クラスを作成してください。
(仕様)
クイズを表すQuizクラスを作成します。次のメンバ変数、コンストラクタ、メソッドを追加し、Quiz.javaとして保存します。

  • メンバ変数の作成
    • 問題文を表すmainをString型で定義します。※privateアクセスとします。
  • コンストラクタの作成
    • 引数:
      • main:String型
    • 処理内容:引数で与えられた値を、同名のメンバ変数に代入します。
  • displayHeaderメソッドの作成
    • 概要:問題の冒頭文を表示します。
    • 引数:なし
    • 戻り値:なし
    • 処理内容:「次の問いに答えなさい」と表示します。(※「」も表示内容です)
  • displayMainメソッドの作成
    • 概要:問題の本文を表示します。
    • 引数:なし
    • 戻り値:なし
    • 処理内容:メンバ変数mainの内容を表示します。

選択肢つきクイズを表すMultipleChoiceQuizクラスを、Quizクラスを継承して作成します。次のメンバ変数、コンストラクタ、メソッドを追加しMultipleChoiceQuiz.javaとして保存します。

  • メンバ変数の作成
    • 選択肢を表すanswersをString型の配列で定義します。
  • コンストラクタの作成
    • 引数:
      • main:String型
      • answers:String型配列
    • 処理内容:
      • 引数mainの値を用いて、親クラスのコンストラクタを呼び出します。
      • 引数answersは、メンバ変数answersにそのまま代入します。
  • displayHeaderメソッドの作成
    • 概要:問題の冒頭文を表示します。
    • 引数:なし
    • 戻り値:なし
    • 処理内容:「次の問いについて、正しいものを4つの中から選びなさい」と表示します。(※「」も表示内容です)
  • displayMainメソッドの作成
    • 概要:問題の本文を表示します。
    • 引数:なし
    • 戻り値:なし
    • 処理内容:
      • メンバ変数mainの内容を表示します。
      • メンバ変数answersの各要素を、「x:yyyyyy」の形式で表示します。
        xは1から始まる連続番号
        yyyyyyはanswersの各要素です。

穴埋めクイズを表すBlankQuizクラスを、Quizクラスを継承して作成します。次のメンバ変数、コンストラクタ、メソッドを追加し、BlankQuiz.javaとして保存します。

  • メンバ変数の作成
    • 空欄の数を表すblankCountをint型で定義します。
  • コンストラクタの作成
    • 引数:
      • main:String型
      • blankCount:int型
    • 処理内容:
      • 引数mainの値を用いて、親クラスのコンストラクタを呼び出します。
      • 引数blankCountは、メンバ変数blankCountにそのまま代入します。
  • displayHeaderメソッドの作成
    • 概要:問題の冒頭文を表示します。
    • 引数:なし
    • 戻り値:なし
    • 処理内容:「次の文の空欄を埋めなさい」と表示します。(※「」も表示内容です)
  • displayMainメソッドの作成
    • 概要:問題の本文を表示します。
    • 引数:なし
    • 戻り値:なし
    • 処理内容:
      • メンバ変数mainの内容を表示します。
      • メンバ変数blankCountの数だけ、「x. ______________」と表示します。
        xは1から始まる連続番号

クイズを表示するためのQuizViewerクラスを作成します。次のクラス変数とクラスメソッドを作成し、QuizViewer.javaとして保存します。

  • クラス変数の作成
    • 問題番号を表すcountをint型で定義します。
  • showQuizメソッドの作成(クラスメソッド)
    • 概要:問題を表示します。
    • 引数:quiz:Quiz型
    • 戻り値:なし
    • 処理内容:
      • メンバ変数countを1加算します。
      • 「<第x問>」と表示します。(xはメンバ変数countの値が入ります。)
      • 引数quizのdisplayHeaderメソッドを呼び出します。
      • 引数quizのdisplayMainメソッドを呼び出します。
      • 改行します。

提供コード

下記のMain.javaを作成した他のソースファイルと同じフォルダ内に保存して動作確認し、実行結果が得られることを確認してください。

public class Main {
    public static void main(String[] args) {
        Quiz q1 = new Quiz("最も面積の広い都道府県はどこですか?");
        String[] answers = {"青りんご","さくらんぼ","みかん","ぶどう"};
        Quiz q2 = new MultipleChoiceQuiz("赤色の果物はどれですか", answers);
        Quiz q3 = new BlankQuiz("(   )は(    )年に鎌倉幕府を設立した。", 2);

        QuizViewer.showQuiz(q1);
        QuizViewer.showQuiz(q2);
        QuizViewer.showQuiz(q3);
    }
}

実行結果

<第1問>
「次の問いに答えなさい」
最も面積の広い都道府県はどこですか?

<第2問>
「次の問いについて、正しいものを4つの中から選びなさい」
赤色の果物はどれですか
1:青りんご
2:さくらんぼ
3:みかん
4:ぶどう

<第3問>
「次の文の空欄を埋めなさい」
(   )は(    )年に鎌倉幕府を設立した。
1. ______________
2. ______________

解答編

それでは、解答編です。

Q001

(Item.java)

public abstract class Item {
    String name;
    int value;

    Item(String name, int value) {
        this.name = name;
        this.value = value;
    }

    public abstract void use();
}

(Buki.java)

public class Buki extends Item{
    Buki(String name, int value) {
        super(name, value);
    }

    public void use() {
        System.out.println(this.name + "でこうげき!!");
        System.out.println("敵に" + this.value + "のダメージ!");
    }
}

(Armor.java)

public class Armor extends Item {
    Armor( String name, int value) {
        super(name,value);
    }
    public void use() {
        System.out.println(this.name + "を身に着けた");
        System.out.println("守備力が" + this.value + "上がった");
    }
}

Q002

(Transferable.java)

public interface Transferable {
    public void transfer();    
}

(Switch.java)

public class Switch implements Transferable {
    public void transfer() {
        System.out.println("MACアドレスを使ってデータを転送します");
    }
}

(Router.java)

public class Router implements Transferable{
    public void transfer() {
        System.out.println("IPアドレスを使ってデータを転送します");
    }    
}

Q003

(Coupon.java)

public interface Coupon {
    public int discount(int amount);
}

(PercentageCoupon.java)

public class PercentageCoupon implements Coupon {
    double rate;

    public PercentageCoupon(double rate) {
        this.rate = rate;
    }
    public int discount(int amount) {
        return (int)(amount * rate);
    }
}

(FixedCoupon.java)

public class FixedCoupon implements Coupon{
    int discountAmount;

    public FixedCoupon(int discountAmount) {
        this.discountAmount = discountAmount;
    }

    public int discount(int amount) {
        return amount - discountAmount;
    }
}

(Casher.java)

public class Casher {
    public static int payment(int amount, Coupon coupon) {
        int ret = coupon.discount(amount);
        return ret;
    }
}

(Main.java)

public class Main {
    public static void main(String[] args) {
        PercentageCoupon coupon1 = new PercentageCoupon(0.3);
        FixedCoupon coupon2 = new FixedCoupon(1000);
        System.out.println(Casher.payment(5000, coupon1));
        System.out.println(Casher.payment(5000, coupon2));

        //①変数coupon3を宣言します。5割引のクーポンを生成し代入します。
    	PercentageCoupon coupon3 = new PercentageCoupon(0.5);
        //②変数coupon4を宣言します。1500円引のクーポンを生成し代入します。
    	FixedCoupon coupon4 = new FixedCoupon(1500);
        //③Casherのpaymentメソッドを呼び出し、5000円に対してcoupon3を適用した結果を表示します。
    	System.out.println(Casher.payment(5000,coupon3));
        //④Casherのpaymentメソッドを呼び出し、5000円に対してcoupon4を適用した結果を表示します。
    	System.out.println(Casher.payment(5000,coupon4));
    }    
}

Q004

(Quiz.java)

public class Quiz {
    private String main;

    public Quiz(String main) {
        this.main = main;
    }

    public void displayHeader() {
        System.out.println("「次の問いに答えなさい」");        
    }

    public void displayMain() {
        System.out.println(main);
    }
}

(MultipleChoiceQuiz.java)

public class MultipleChoiceQuiz extends Quiz{
    String[] answers;

    public MultipleChoiceQuiz(String main, String[] answers) {
        super(main);
        this.answers = answers;
    }

    public void displayHeader() {
        System.out.println("「次の問いについて、正しいものを4つの中から選びなさい」");
    }

    public void displayMain() {
        super.displayMain();
        for (int i = 0; i < answers.length; i++) {
            System.out.println( (i+1) + ":" + answers[i] );
        }
    }
}

(BlankQuiz.java)

public class BlankQuiz extends Quiz {
    int blankCount;

    public BlankQuiz(String main, int blankCount) {
        super(main);
        this.blankCount = blankCount;
    }

    public void displayHeader() {
        System.out.println("「次の文の空欄を埋めなさい」");
    }

    public void displayMain() {
        super.displayMain();
        for (int i = 0; i < blankCount; i++) {
            System.out.println( (i+1) + ". ______________" );
        }
    }
}

(QuizViewer.java)

public class QuizViewer {
    public static int count;

    public static void showQuiz(Quiz quiz) {
        count++;
        System.out.println("<第" + count + "問>");
        quiz.displayHeader();
        quiz.displayMain();
        System.out.println();
    }
}

おわりに

本日は以上となります。最後までご覧くださりありがとうございます。初学者の方が多態性の動作イメージをつかむ一助になれば幸いです。ひきつづき、問題の提供をしていければと思っています。今後もよろしくお願いいたします。


合同会社イー・シー・エフでは、子ども向けプログラミングなどの教育講座を実施しています。プログラミング教室の案内や教育教材の情報、また関連するご相談・問い合わせにつきましては下記よりご確認ください。

ECFエデュケーション
タイトルとURLをコピーしました