Java | 1 日 90 分 × 7 日アプリ学習 初級編:コンストラクタ入門アプリ

Web APP Java
スポンサーリンク

2日目のゴール

2日目のテーマは
「コンストラクタで“どこまで初期化するか”を自分で設計できるようになること」 です。

1日目であなたはすでに、

コンストラクタ=new された瞬間に呼ばれる特別メソッド
初期化=「生まれた直後の状態を整えること」

というイメージをつかみました。

2日目ではここから一歩進んで、

「どんな状態で生まれてきてほしいか」を自分で決める
「いくつかのパターンで生まれさせる」ことを考える
「初期化をバラバラに書かず、コンストラクタに集める」感覚を強くする

ここを、具体的な例を通して固めていきます。


1日目の Player をもう一度思い出す

「生まれた瞬間にちゃんとした状態になる」感覚

1日目の Player はこんな感じでした。

public class Player {
    String name;
    int hp;

    Player(String name) {
        this.name = name;
        this.hp = 100;
    }

    void showStatus() {
        System.out.println("名前: " + name);
        System.out.println("HP : " + hp);
    }
}
Java
public class Main {
    public static void main(String[] args) {
        Player p = new Player("勇者");
        p.showStatus();
    }
}
Java

ここでのポイントは、

new Player("勇者") と書いた瞬間に
「名前が勇者で、HP が 100 の Player」が必ず生まれる

という“安心感”でした。

2日目では、この「安心感」をもっと設計できるようにしていきます。


「初期化をコンストラクタに集める」と何が嬉しいか

バラバラ代入と比べてみる

まず、コンストラクタを使わないパターンをもう一度見てみます。

public class Player {
    String name;
    int hp;
}
Java
public class Main {
    public static void main(String[] args) {
        Player p = new Player();
        p.name = "勇者";
        p.hp = 100;
        p.hp = p.hp - 30;
    }
}
Java

この書き方だと、

name を設定し忘れてもコンパイルエラーにならない
hp を設定し忘れても、そのまま 0 で動いてしまう

つまり、「中途半端な状態の Player」が簡単に生まれてしまいます。

一方、コンストラクタに初期化を集めるとこうなります。

public class Player {
    String name;
    int hp;

    Player(String name) {
        this.name = name;
        this.hp = 100;
    }
}
Java
public class Main {
    public static void main(String[] args) {
        Player p = new Player("勇者");
    }
}
Java

この形だと、

名前を渡さないとコンパイルエラー
HP を設定し忘れることもない(コンストラクタの中で必ず 100 にしている)

という「強いルール」を作れます。

ここでの本質は、

「初期化をコンストラクタに集めると、“変な状態のオブジェクト”が生まれにくくなる」

ということです。


「初期化のパターンが複数ある」場合を考えてみる

例:HP を変えたいとき、どうする?

ゲームを少しだけリアルにしてみます。

普通のプレイヤーは HP 100
上級者プレイヤーは HP 200

こういう仕様にしたくなったとします。

やり方はいくつかありますが、
まず「悪い例」から見てみます。

public class Main {
    public static void main(String[] args) {
        Player normal = new Player("初心者");
        Player advanced = new Player("上級者");

        advanced.hp = 200;  // 後から書き換える
    }
}
Java

動きます。
でも、これだと「上級者の HP を 200 にする」というルールが main に散らばります。

別の場所で上級者を作るとき、また同じことを書かないといけない
書き忘れると、上級者なのに HP 100 のままになる

こういう「ルールがバラバラに散らばる」状態は、あとで必ずしんどくなります。


コンストラクタを“複数用意する”という考え方

コンストラクタのオーバーロード

ここで出てくるのが、
「コンストラクタを複数定義する(オーバーロード)」 という考え方です。

Player に、こういうコンストラクタを追加してみます。

public class Player {
    String name;
    int hp;

    Player(String name) {
        this.name = name;
        this.hp = 100;
    }

    Player(String name, int hp) {
        this.name = name;
        this.hp = hp;
    }

    void showStatus() {
        System.out.println("名前: " + name);
        System.out.println("HP : " + hp);
    }
}
Java

これで、こういう使い方ができます。

public class Main {
    public static void main(String[] args) {
        Player normal = new Player("初心者");        // HP 100
        Player advanced = new Player("上級者", 200); // HP 200

        normal.showStatus();
        advanced.showStatus();
    }
}
Java

ここでのポイントは、

Player(String name)Player(String name, int hp)
同じ名前(Player)だけど、引数の数が違うコンストラクタを2つ定義している
呼び出し側は、渡す引数の数で「どのコンストラクタを使うか」を選べる

ということです。

これにより、

「普通のプレイヤーは名前だけ渡す」
「HP を指定したいときは、名前と HP を渡す」

という2パターンの“生まれ方”を、
コンストラクタで表現できるようになります。


初期化ロジックを“1か所にまとめる”テクニック

this(…) を使ってコンストラクタ同士をつなぐ

さっきの Player には、ちょっとだけ気になる点があります。

Player(String name) {
    this.name = name;
    this.hp = 100;
}

Player(String name, int hp) {
    this.name = name;
    this.hp = hp;
}
Java

name を代入するコードが、2か所に重複しています。
こういう「同じことを2回書く」は、あとで変更するときにミスの元になります。

そこで使えるのが、
this(...) を使って、コンストラクタから別のコンストラクタを呼ぶ というテクニックです。

こう書き換えられます。

public class Player {
    String name;
    int hp;

    Player(String name) {
        this(name, 100);
    }

    Player(String name, int hp) {
        this.name = name;
        this.hp = hp;
    }

    void showStatus() {
        System.out.println("名前: " + name);
        System.out.println("HP : " + hp);
    }
}
Java

ここで何が起きているか、丁寧に追ってみます。

Player(String name) が呼ばれたとき
最初の行 this(name, 100); が実行される
これは「同じクラスの別のコンストラクタ Player(String name, int hp) を呼ぶ」という意味
結果として、「名前と HP を指定するコンストラクタ」が呼ばれ、
this.name = name; this.hp = hp; が実行される

つまり、

「最終的な初期化ロジックは、Player(String name, int hp) に1か所だけ書いてある」

という状態になります。

これがめちゃくちゃ大事です。


「初期化の中心」をどこに置くかを意識する

ルールは1か所に集めると強くなる

さっきの Player をもう一度見ます。

Player(String name) {
    this(name, 100);
}

Player(String name, int hp) {
    this.name = name;
    this.hp = hp;
}
Java

ここでの設計はこうです。

「Player の本当の初期化ルール」は Player(String name, int hp) に書く
「HP を 100 にしたいだけのとき」は、そこに委ねる

このように、

「初期化の中心となるコンストラクタ」を1つ決めて、他のコンストラクタはそこに寄せる

という考え方は、現場のコードでもよく使われます。

もし将来、「初期 HP を 150 にしたい」となったら、
Player(String name, int hp) の中身を変えるだけで済みます。

Player(String name, int hp) {
    this.name = name;
    this.hp = hp + 50;  // 例えばこういう仕様にしてもいい
}
Java

Player(String name) のほうは、
this(name, 100); のままでOKです。
「中心」が1か所にあるからこそ、変更に強くなります。


2日目のミニアプリ:難易度付き Player

仕様を言葉で決める

Player クラスを作る
Player は名前と HP を持つ
普通のプレイヤーは HP 100
「難易度ハード」のプレイヤーは HP 50
main で、2種類のプレイヤーを作って状態を表示する

これをコンストラクタで表現してみます。

public class Player {
    String name;
    int hp;

    Player(String name) {
        this(name, 100);
    }

    Player(String name, int hp) {
        this.name = name;
        this.hp = hp;
    }

    void showStatus() {
        System.out.println("名前: " + name);
        System.out.println("HP : " + hp);
    }
}
Java
public class Main {
    public static void main(String[] args) {
        Player normal = new Player("ノーマル勇者");
        Player hard = new Player("ハード勇者", 50);

        normal.showStatus();
        System.out.println("-----");
        hard.showStatus();
    }
}
Java

実行イメージはこんな感じです。

名前: ノーマル勇者
HP : 100
-----
名前: ハード勇者
HP : 50

ここで感じてほしいのは、

「難易度の違い」という“ゲームのルール”が、
main にバラバラに書かれているのではなく、
コンストラクタの形として表現されている

ということです。


今日いちばん大事な“頭の中の整理”

初期化=「どんな状態で生まれてきてほしいか」を決めること

2日目で絶対に持って帰ってほしいのは、この感覚です。

初期化とは
「このクラスのオブジェクトは、こういう状態で生まれてきてほしい」という“約束”を決めること。

コンストラクタとは
その約束をコードとして書く場所。
new された瞬間に必ず呼ばれる、“初期化専用の特別メソッド”。

複数のコンストラクタを持つ意味
「生まれ方のパターン」を増やすこと。
引数の違いで、「どう初期化するか」を選べるようにする。

this(…) を使う意味
初期化ロジックの“中心”を1か所に集めるため。
同じことを何度も書かず、変更に強いコードにするため。

そして、

「このクラスは、どんな状態で生まれてきてほしい?」
「そのパターンはいくつある?」
「初期化の中心はどのコンストラクタに置く?」

と自分に問いかけながらコンストラクタを書く——
この思考ができていたら、2日目は完璧です。

3日目以降は、
コンストラクタと他のクラス(例えば装備・ステータス・設定クラスなど)を組み合わせて、
「複数のオブジェクトをまとめて初期化する」世界に進んでいけます。

タイトルとURLをコピーしました