未来エンジニア養成所Blog

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

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

title


問題2-9

雑誌を表すMagazineクラスを作成してください。

本を表すBookクラスはすでに完成しています。
(変更は禁止です)

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


【Magazineクラス】

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

  2. スーパークラスから受け継いだ2つのインスタンスフィールド(タイトル、価格)のほかに、表紙に掲載されているタレント名を保持するためのcoverPersonNameインスタンスフィールド(String型)を定義します。

  3. 引数にタイトル、価格、表紙タレント名の3つの値を受け取るコンストラクタを定義します。
    そのうち、タイトル、価格の2つの値は、スーパークラスのコンストラクタを利用して受け渡します。

  4. 雑誌の内容を紹介するshowインスタンスメソッドを定義します。
    出力内容は、下記実行結果を参考にしてください。


【実行結果】

東京Runner絶賛発売中!!
定価650円
今回の表紙:上野彩さん


【InheritanceConstructorPractice.java】

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

        // Magazineクラスのオブジェクトを生成
        Magazine magazine = new Magazine("東京Runner", 650, "上野彩");

        // 雑誌の内容紹介メソッドの呼び出し
        magazine.show();

    }
}


// Bookクラス
class Book {

    // タイトル
    private String title;

    // 価格
    private int price;

    // コンストラクタ
    public Book(String title, int price) {
        this.title = title;
        this.price = price;
    }

    // タイトル取得メソッド
    public String getTitle() {
        return title;
    }

    // 価格取得メソッド
    public int getPrice() {
        return price;
    }

}


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


解答例

【InheritanceConstructorPractice.java】

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

        // Magazineクラスのオブジェクトを生成
        Magazine magazine = new Magazine("東京Runner", 650, "上野彩");

        // 雑誌の内容紹介メソッドの呼び出し
        magazine.show();

    }
}

// Bookクラス
class Book {

    // タイトル
    private String title;

    // 価格
    private int price;

    // コンストラクタ
    public Book(String title, int price) {
        this.title = title;
        this.price = price;
    }

    // タイトル取得メソッド
    public String getTitle() {
        return title;
    }

    // 価格取得メソッド
    public int getPrice() {
        return price;
    }

}

// Magazineクラス
class Magazine extends Book {

    // 表紙タレント名
    private String coverPersonName;

    // コンストラクタ
    public Magazine(String title, int price, String coverPersonName) {

        super(title, price);

        this.coverPersonName = coverPersonName;
    }

    // 雑誌の内容紹介メソッド
    public void show() {
        System.out.println(getTitle() + "絶賛発売中!!");
        System.out.println("定価" + getPrice() + "円");
        System.out.println("今回の表紙:" + coverPersonName + "さん");
    }
}


解説

今回の問題は基本的な内容ですが、結構つまずいた人もいるかと思います。

コンパイルエラーのメッセージを確認して自力で修正できた人は問題ありませんが、エラーメッセージの意味が良くわからなかった人は解説をよく読んでしっかり理解しておきましょう。



今回の問題は、実は継承よりコンストラクタの正しい理解が重要です。

まずは次のプログラムを見てください。

class Super {

}

class Sub extends Super {

}



全く問題のないプログラムで、コンパイルもちゃんと通ります。

この2つのクラスにはコンストラクタが定義されていません。

でも、コンストラクタを定義していないクラスには、自動的に引数なしの「デフォルトコンストラクタ」と呼ばれるものが挿入される仕組みになっています。

class Super {
    // デフォルトコンストラクタ
    public Super() {

    }
}

class Sub extends Super {
    // デフォルトコンストラクタ
    public Sub() {

    }
}



そして、ここからが重要です。

コンストラクタの1行目には、別のコンストラクタ呼び出しを記述できます。

コンストラクタをオーバーロードしている場合などは、「this(10);」といったように呼び出せます。

class Sub extends Super {
    public Sub() {
        this(10);
    }
    public Sub(int i) {

    }
}



実は、コンストラクタの1行目にコンストラクタ呼び出しを記述しなかった場合、自動的に「デフォルトコンストラクタ呼び出し」と呼ばれるものが挿入されます。

class Super {
    public Super() {

    }
}

class Sub extends Super {
    public Sub() {
        // デフォルトコンストラクタ呼び出し
        super();
    }
}



「super();」とは、スーパークラスの引数なしコンストラクタの呼び出しです。

つまり、コンストラクタはスーパークラスから順に実行されてサブクラスに降りていく仕組みになっています。



それを踏まえて、次のプログラムを見てください。

class Super{
    public Super(int i) {

    }
}

class Sub extends Super {

}



このプログラムはコンパイルエラーになります。

理由は分かるでしょうか。


このプログラムに「デフォルトコンストラクタ」「デフォルトコンストラクタ呼び出し」を記述すればすぐに分かるでしょう。

class Super {
    public Super(int i) {

    }
}

class Sub extends Super {
    public Sub() {
        super();
    }
}



Subクラスのコンストラクタの1行目、「super();」はスーパークラスの引数なしコンストラクタ呼び出しですが、Superクラスには引数なしコンストラクタが存在しないためにコンパイルエラーとなります。

たとえば、上記プログラムを次のように書き直せばコンパイルは通ります。

class Super {
    public Super(int i) {

    }
}

class Sub extends Super {
    public Sub() {
        super(10);
    }
}



このように、スーパークラスとサブクラスのコンストラクタをうまく連結することが重要です。



問題に戻ります。

次のように記述した人も多いと思います。

// コンストラクタ
public Magazine(String title, int price, String coverPersonName) {
    this.title = title;
    this.price = price;
    this.coverPersonName = coverPersonName;
}



これではコンパイルが通りません。

もう理由は分かりますよね。


このMagazineコンストラクタの1行目には、「super();」が自動挿入されているからです。



しかし、もしBookクラスの引数ありコンストラクタを消したとしても、コンパイルは通りません。

なぜなら、Bookクラスの2つのインスタンスフィールドは、アクセス修飾子がprivateだからです。


スーパークラスのprivateなフィールド・メソッドもサブクラスにはきちんと引き継がれます。

しかし、サブクラスから直接アクセスは禁止されます。



同じ理由で、次のプログラムもコンパイルエラーです。

このように記述した人も多かったのではないでしょうか。

// 雑誌の内容紹介メソッド(間違い)
public void show() {
    System.out.println(title + "絶賛発売中!!");
    System.out.println("定価" + price + "円");\
    System.out.println("今回の表紙:" + coverPersonName + "さん");
}



でもあきらめる必要はありません。

2つのインスタンスフィールドには、データ取得用のゲッターメソッドがきちんと定義されています。

それを呼び出せばすべて解決です。


参考図書



LINE公式アカウント

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


LineOfficial

友だち追加