未来エンジニア養成所Blog

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

【Java】オブジェクト指向の応用問題3-9

title


問題3-9

学校を表現するSchoolクラスと、その学校に在学する生徒を表現するStudentクラスを作成してください。
ただし、StudentクラスはSchoolクラスの中だけで使えるprivateな非staticネストクラスにしてください。


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


【Schoolクラス】

  1. 定員人数を表現するint型の定数CAPACITYを宣言します。
    初期値に「5」を設定してください。

  2. 次の2つのインスタンスフィールドを持ちます。
      ・学校名を表すname(String型)インスタンスフィールド
      ・在校生を表す配列students(Student[]型)インスタンスフィールド

  3. コンストラクタでは引数として学校名(String型)を受け取ります。
    そのままインスタンスフィールドに値を格納してください。
    また、このタイミングで定員人数分の在校生配列オブジェクトを生成します。

  4. 入学メソッドenterSchoolを定義します。
    引数は生徒名で、在校生配列の先頭から空き(つまりnull)を検索し、空きがあればStudentクラスのインスタンスを生成して配列要素として格納します。
    出席番号は1から順に割り当てます。
    その際に「○○さんが△△に入学しました」と出力してください。
    もし定員人数を超えてしまう場合は「定員オーバーで○○さんは△△に入学できません」と表示して入学を見送ります。

  5. 在校生紹介メソッドintroduceを定義します。
    在校生配列の先頭から、在校生がいれば(つまりnullでなければ)toStringメソッドを呼び出して自己紹介させます。

  6. privateな非staticネストクラスStudentを定義します。


【Studentネストクラス】

  1. 次の2つのインスタンスフィールドを持ちます。
      ・出席番号を表すid(int型)インスタンスフィールド
      ・生徒名を表すname(String型)インスタンスフィールド

  2. コンストラクタでは引数として出席番号(int型)と生徒名(String型)を受け取ります。
    そのままインスタンスフィールドに値を格納してください。

  3. toStringメソッドをオーバーライドして、自己紹介文を戻り値として返します。
    実装は下記実行結果を参考にしてください。


【実行結果】

春日さんがJava学園に入学しました
若林さんがJava学園に入学しました
遠藤さんがJava学園に入学しました
田中さんがJava学園に入学しました
渡辺さんがJava学園に入学しました
定員オーバーで山下さんはJava学園に入学できません

Java学園に在学している出席番号1の春日です。
Java学園に在学している出席番号2の若林です。
Java学園に在学している出席番号3の遠藤です。
Java学園に在学している出席番号4の田中です。
Java学園に在学している出席番号5の渡辺です。


【NestClassBasicPractice.java】

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

        // 学校の設立
        School shool = new School("Java学園");

        // 生徒が続々と入学
        school.enterSchool("春日");
        school.enterSchool("若林");
        school.enterSchool("遠藤");
        school.enterSchool("田中");
        school.enterSchool("渡辺");

        // 定員オーバー
        school.enterSchool("山下");

        System.out.println();

        // 在校生の紹介
        school.introduce();

    }
}


// ここに学校クラスを作成してください
// さらに、生徒ネストクラスを作成してください


解答例

【NestClassBasicPractice.java】

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

        // 学校の設立
        School school = new School("Java学園");

        // 生徒が続々と入学
        school.enterSchool("春日");
        school.enterSchool("若林");
        school.enterSchool("遠藤");
        school.enterSchool("田中");
        school.enterSchool("渡辺");

        // 定員オーバー
        school.enterSchool("山下");

        System.out.println();

        // 在校生の紹介
        school.introduce();

    }
}

// 学校クラス
class School {

    // 定員数定数
    public static final int CAPACITY = 5;

    // 学校名
    private String name;

    // 在校生配列
    private Student[] students;

    // 生徒ネストクラス
    private class Student {

        // 出席番号
        private int id;

        // 生徒名
        private String name;

        // コンストラクタ
        public Student(final int id, final String name) {
            this.id = id;
            this.name = name;
        }

        @Override
        public String toString() {
            return School.this.name + "に在学している出席番号" + id + "の" + name + "です。";
        }
    }

    // コンストラクタ
    public School(final String name) {

        this.name = name;

        // 定員分の空きを確保
        students = new Student[CAPACITY];
    }

    // 入学メソッド
    public void enterSchool(final String name) {

        for(int i = 0; i < students.length; i++) {

            // 空きがあれば
            if(students[i] == null) {
                students[i] = new Student(i + 1, name);
                System.out.println(name + "さんが" + this.name + "に入学しました");
                return;
            }
        }

        System.out.println("定員オーバーで" + name + "さんは" + this.name + "に入学できません");
    }

    // 在校生紹介メソッド
    public void introduce() {

        for(int i = 0; i < students.length; i++) {

            // 在校生がいる場合
            if(students[i] != null) {
                System.out.println(students[i]);
            } else {
                break;
            }
        }
    }
}


解説

クラスのメンバと言えば「フィールド」「メソッド(コンストラクタ)」を思い浮かべるでしょう。

しかし、実は「クラス」もメンバにすることができます。
(インタフェースや列挙型なども含みます)



一般的なクラスを「トップレベルクラス」といい、それ以外の「トップレベルクラスに含まれるクラス」のことを「ネストクラス」と言います。


「ネストクラス」には「メンバクラス(staticと非staticの2種類)」「ローカルインナークラス」「無名(匿名)クラス」などがありますが、今回は非staticネストクラス(メンバクラス)がテーマです。



非staticネストクラスを理解するうえで一番大切なことは、それを含む外側のクラス(エンクロージングクラスといいます)のインスタンスがないと、内側のクラス、つまり非staticネストクラスのインスタンスが生成できない点です。

そして、非staicネストクラスのインスタンスは「2つのthis」を持ちます。

外側のクラスのインスタンスを表すthisと、内側のクラスのインスタンスを表すthisです。

今回の問題で一番の難点が、この「2つのthis」です。



今回の問題で言えば、外側のクラスが学校クラス、内側のクラスが生徒クラスです。

そして、学校クラスも生徒クラスもnameというインスタンスフィールドを持っています。

生徒クラスのインスタンスは学校クラスのインスタンスに含まれているわけですから、生徒クラスのインスタンスは「学校名」と「生徒名」の両方を持っています。


実は、thisの前には、クラス名を記述できます。

生徒クラスのtoStringメソッドを見てみましょう。

public String toString() {
    return School.this.name + "に在学している出席番号" + id + "の" + name + "です。";
}


「name」あるいは「this.name」と記述すれば、「このクラスのname」という意味なので、生徒クラスのname、つまり、生徒名になります。

よって、「School.this.name」と、外側のクラス名を明示することで外側クラスのname、つまり、学校名を取得できます。



「ネストクラス」はJava初級者には苦手な人が多いようです。

しかし「メンバクラス(staticと非staticの両方)」と「無名(匿名)クラス」は、高度なJava開発には欠かせない技術です。

少し慣れるまで時間がかかりますが、しっかりマスターしておきましょう。


参考図書



LINE公式アカウント

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


LineOfficial

友だち追加



【まついのLINE公式アカウントはこちらから!】
Line公式アカウント