未来エンジニア養成所Blog

月単価180万以上のプログラミング講師がプログラミングを皆に楽しんでもらうための情報をお届けします。

【Java】オブジェクト指向の基本問題2-10

title


問題2-10

目覚まし時計を表すAlarmClockクラスを作成してください。

普通の時計を表すClockクラスはすでに完成しています。
(変更は禁止です)

また、AlarmClockクラスを使用するOverrideBasicPracticeクラスのmainメソッドはすでに完成しています。
(変更は禁止です)


【AlarmClockクラス】

  1. Clockクラスを継承します。

  2. スーパークラスから受け継いだ3つのインスタンスフィールド(時・分・秒)のほかに、アラーム時刻(時・分)を表すalarmHourとalarmMinuteインスタンスフィールド(int型)を定義します。

  3. 5つの引数の値を受け取るコンストラクタを定義します。
    そのうち、時・分・秒の3つの値は、スーパークラスのコンストラクタを利用してインスタンスフィールドに受け渡します。

  4. スーパークラスにあるshowDataインスタンスメソッドを適切にオーバーライドします。
    出力内容は、下記実行結果を参考にしてください。


【実行結果】

ただいまの時刻:10時15分30秒
ただいまの時刻:15時45分20秒
アラーム設定時刻:6時30分


【OverrideBasicPractice.java】

public class OverrideBasicPractice {
    public static void main(String[] args) {

        // 普通の時計オブジェクトの生成
        Clock c1 = new Clock(10, 15, 30);

        // 普通の時計の情報の表示
        c1.showData();

        System.out.println();

        // 目覚まし時計オブジェクトの生成
        AlarmClock c2 = new AlarmClock(15, 45, 20, 6, 30);

        // 目覚まし時計の情報の表示
        c2.showData();

    }
}


// 時計クラス
class Clock {

    // 時分秒
    private int hour;
    private int minute;
    private int second;

    // コンストラクタ
    public Clock(int hour, int minute, int second) {

        this.hour = hour;
        this.minute = minute;
        this.second = second;

    }

    // 情報表示メソッド
    public void showData() {
        System.out.println("ただいまの時刻:" + hour + "時" + minute + "分" + second + "秒");
    }

}


// ここにAlarmClockクラスを作成してください


解答例

【OverrideBasicPractice.java】

public class OverrideBasicPractice {
    public static void main(String[] args) {

        // 普通の時計オブジェクトの生成
        Clock c1 = new Clock(10, 15, 30);

        // 普通の時計の情報の表示
        c1.showData();

        System.out.println();

        // 目覚まし時計オブジェクトの生成
        AlarmClock c2 = new AlarmClock(15, 45, 20, 6, 30);

        // 目覚まし時計の情報の表示
        c2.showData();

    }
}

// 時計クラス
class Clock {

    // 時分秒
    private int hour;
    private int minute;
    private int second;

    // コンストラクタ
    public Clock(int hour, int minute, int second) {

        this.hour = hour;
        this.minute = minute;
        this.second = second;

    }

    // 情報表示メソッド
    public void showData() {
        System.out.println("ただいまの時刻:" + hour + "時" + minute + "分" + second + "秒");
    }

}

// 目覚まし時計クラス
class AlarmClock extends Clock {

    // アラーム時刻(時・分)
    private int alarmHour;
    private int alarmMinute;

    // コンストラクタ
    public AlarmClock(int hour,
            int minute,
            int second,
            int alarmHour,
            int alarmMinute) {

        super(hour, minute, second);
        this.alarmHour = alarmHour;
        this.alarmMinute = alarmMinute;
    }

    // 情報表示メソッド(オーバーライド)
    @Override
    public void showData() {
        super.showData();
        System.out.println("アラーム設定時刻:" + alarmHour + "時" + alarmMinute + "分");
    }
}


解説

オブジェクト指向と言えば「継承」は重要ですが、それに付随して「オーバーライド」も超重要です。

しっかり感覚をつかんでおきましょう。



「継承」を行うと、サブクラスはスーパークラスのメンバ(フィールドやメソッド)を受け継ぐことが可能です。

しかし、受け継いだメソッドをそのまま使いたくない、カスタマイズして使いたい場合も出てきます。

その時に、サブクラス側で受け継いだメソッドを再定義することが可能なんです。

これこそが「オーバーライド」です。



オーバーライドの方法は簡単です。

スーパークラスで定義してあるとおりに、同じメソッド名、引数、戻り値の型を記述して定義すればOKです。
(ただし、クラスメソッドやprivateなメソッドはオーバーライドできません)


そしてオーバーライドの大切なマナーとして、「@Overrideアノテーション」を付けるようにしましょう。

これはJDK5.0から導入されたものですが、簡単にいうと「コンパイラによってチェックされるコメントのようなもの」です。

オーバーライドは偶然に行われるものではなく、プログラマの強い意志で行うものです。

それを強調するのが、「@Overrideアノテーション」だと思ってください。



ここで問題に戻りましょう。

showDataメソッドのオーバーライドをこんな風にコーティングしてしまい、コンパイルが通らない人も多かったのではないでしょうか。

// 情報表示メソッド(間違い)
@Override
public void showData() {
    System.out.println("ただいまの時刻:" + hour + "時" + minute + "分" + second + "秒");
    System.out.println("アラーム設定時刻:" + alarmHour + "時" + alarmMinute + "分");
}



これは、オーバーライド失敗というより、もっと基本的なミスです。

Clockクラスのhour、minute、secondインスタンスフィールドのアクセス修飾子がprivateのため、サブクラスから直接アクセスできないのがコンパイルエラーの原因です。



しかし、そのことに気が付いたとしても、解決できない人が多かったかもしれません。

なぜなら、Clockクラスには3つのprivateインスタンスフィールドへのゲッターメソッドが定義されていないからです。

一体どうやってアクセスするのでしょうか。



答えは「スーパークラスの3つのインスタンスフィールドにアクセスしない」です。


ここで、継承に関して次のことをしっかり理解しておいてください。

スーパークラスから受け継いだメソッドをオーバーライドしてカスタマイズすることは可能ですが、だからといってスーパークラスから受け継いだメソッドが消えてしまうわけではないんです。


つまり、サブクラスのインスタンスは「スーパークラスから受け継いだオーバーライド前のメソッド」も、「サブクラスでオーバーライドしたメソッド」も両方持っているのです。


ただ、メソッドをオーバーライドすると、オーバーライドされた側よりオーバーライドした側のメソッドが優先的に呼び出される仕組みになっているだけです。

オーバーライドしたものの、やっぱりオーバーライド前のメソッドを使いたい場合はキーワード「super」を付加して呼び出します。

// 情報表示メソッド(オーバーライド)
@Override
public void showData() {
    super.showData();
    System.out.println("アラーム設定時刻:" + alarmHour + "時" + alarmMinute + "分");
}



スーパークラスのprivateなフィールドにはどうやってもアクセスできないので、それらフィールドの値を出力するpublicなメソッドを呼び出してあげるわけです。


参考図書



LINE公式アカウント

仕事が辛くてたまらない人生が、仕事が楽しくてたまらない人生に変わります。
【登録いただいた人全員に、無料キャリア相談プレゼント中!】


LineOfficial

友だち追加