3日目のゴール
3日目のテーマは
「コンストラクタで“ただ値を入れる”から、“ちゃんと意味のある状態を作る”にレベルアップすること」 です。
1〜2日目であなたはすでに、
コンストラクタ=new された瞬間に呼ばれる特別メソッド
初期化=「生まれた直後の状態を整えること」
コンストラクタを複数用意して“生まれ方のパターン”を表現できる
というところまで来ています。
3日目ではここから一歩進んで、
「とりあえず代入」ではなく「意味のある初期状態」を設計する
「変な値が入らないようにする」初期化を考える
「他のクラスと組み合わせて初期化する」イメージを持つ
ここを、少し“アプリっぽい”例で固めていきます。
今日の題材:ユーザー登録ミニアプリで考える
「ユーザー」という現実の存在をクラスにする
現実のアプリをイメージしてみます。
ユーザーがいる
ユーザーには名前や年齢がある
ユーザー登録のときに「おかしな値」は弾きたい
これを Java のクラスにすると、まずはこうなります。
public class User {
String name;
int age;
}
Javaそして、こう使えます。
public class Main {
public static void main(String[] args) {
User u = new User();
u.name = "太郎";
u.age = 20;
}
}
Java動きます。
でも、ここには問題が潜んでいます。
「変な状態のオブジェクト」が簡単に生まれてしまう
ありえないユーザーが作れてしまう
さっきの User は、こういうこともできます。
User u1 = new User();
u1.name = null;
u1.age = -5;
User u2 = new User();
// name も age も設定しないまま使う
Java現実世界で考えると、
名前が null のユーザー
年齢がマイナスのユーザー
名前も年齢も決まっていないユーザー
どれも「ありえない状態」ですよね。
でも、コンパイルエラーにはなりません。
つまり、
「変な状態の User が簡単に生まれてしまう」
ということです。
3日目でやりたいのは、
この「変な状態」をコンストラクタで防ぐ、という発想です。
コンストラクタで「ありえない状態」を防ぐ
必須情報をコンストラクタで受け取る
まずは、名前と年齢を必須にします。
public class User {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
void show() {
System.out.println("名前: " + name + ", 年齢: " + age);
}
}
Java使い方はこうなります。
public class Main {
public static void main(String[] args) {
User u = new User("太郎", 20);
u.show();
}
}
Javaここで起きていることはシンプルです。
new User(“太郎”, 20) と書かないと、User は作れない
「名前なし」「年齢なし」の User はコンパイルエラーになる
これだけでも、かなり“変な状態”を防げます。
でも、まだ足りません。
年齢にマイナスを渡すことはできてしまいます。
User u = new User("太郎", -5); // コンパイルは通る
Javaここを、もう一段ちゃんと考えます。
コンストラクタの中で「値のチェック」をする
初期化のときに“おかしな値”を弾く
User のコンストラクタを、こう変えてみます。
public class User {
String name;
int age;
User(String name, int age) {
if (name == null || name.isEmpty()) {
System.out.println("名前が空です。'不明' にします。");
this.name = "不明";
} else {
this.name = name;
}
if (age < 0) {
System.out.println("年齢がマイナスです。0 にします。");
this.age = 0;
} else {
this.age = age;
}
}
void show() {
System.out.println("名前: " + name + ", 年齢: " + age);
}
}
Javaこれを使ってみます。
public class Main {
public static void main(String[] args) {
User u1 = new User("太郎", 20);
User u2 = new User("", -5);
u1.show();
u2.show();
}
}
Java実行イメージはこんな感じです。
名前が空です。'不明' にします。
年齢がマイナスです。0 にします。
名前: 太郎, 年齢: 20
名前: 不明, 年齢: 0
ここでの本質は、
「コンストラクタの中で、値のチェックと補正をしている」
ということです。
これにより、
User を new した瞬間に、
「少なくともおかしすぎる状態ではない」ことが保証されます。
「初期化=ただ代入」ではない
ルールを埋め込む場所でもある
ここまでの User を見てみると、
コンストラクタは単なる「代入の場所」ではなくなっています。
名前が null や空文字なら「不明」にする
年齢がマイナスなら 0 にする
という「アプリとしてのルール」が、
コンストラクタの中に書かれています。
つまり、
初期化=「このクラスのオブジェクトは、こういうルールで生まれてくる」ことを決める作業
と言えます。
2日目までは「値をセットする」イメージが強かったと思いますが、
3日目ではそこに「ルール」という視点を足してほしいんです。
他のクラスと“まとめて初期化”するイメージ
例:プロフィールを持つユーザー
もう一歩だけ進めてみます。
User が「プロフィール情報」を持つようにしてみましょう。
プロフィールには、自己紹介文があるとします。
public class Profile {
String bio;
Profile(String bio) {
if (bio == null || bio.isEmpty()) {
this.bio = "よろしくお願いします。";
} else {
this.bio = bio;
}
}
void show() {
System.out.println("自己紹介: " + bio);
}
}
JavaUser に Profile を持たせます。
public class User {
String name;
int age;
Profile profile;
User(String name, int age, String bio) {
if (name == null || name.isEmpty()) {
System.out.println("名前が空です。'不明' にします。");
this.name = "不明";
} else {
this.name = name;
}
if (age < 0) {
System.out.println("年齢がマイナスです。0 にします。");
this.age = 0;
} else {
this.age = age;
}
this.profile = new Profile(bio);
}
void show() {
System.out.println("名前: " + name + ", 年齢: " + age);
profile.show();
}
}
Java使い方はこうです。
public class Main {
public static void main(String[] args) {
User u1 = new User("太郎", 20, "Java 勉強中です!");
User u2 = new User("", -5, "");
u1.show();
System.out.println("-----");
u2.show();
}
}
Javaここで起きていることを整理します。
User のコンストラクタの中で、Profile も new している
User を new した瞬間に、「プロフィール付きの User」が完成する
Profile の中でも、自己紹介文のチェックと補正をしている
つまり、
「User を new するだけで、User と Profile の両方が“意味のある状態”で初期化される」
という状態になっています。
これが、「他のクラスと組み合わせて初期化する」イメージです。
初期化を“途中で止めない”という感覚
「new したら、もう使える状態」が理想
3日目で一番大事にしてほしいのは、この感覚です。
new User(...) と書いた瞬間に、
その User は「すぐに使っていい状態」になっているべき
ということです。
逆に、こういうコードが出てきたら要注意です。
User u = new User();
// ここから先で、いろいろ設定しないと使えない
u.name = "太郎";
u.age = 20;
// どこかで profile を new し忘れるかもしれない
Javaこれは、
「初期化がバラバラに散らばっていて、途中で止まる可能性がある」
状態です。
コンストラクタに初期化を集める、
コンストラクタの中で値のチェックや補正をする、
必要なら他のクラスも一緒に new する——
こうすることで、
「new した瞬間に、もう安心して使える」
オブジェクトになります。
3日目のミニアプリ完成形
コードをまとめて眺めてみる
User と Profile を使った、3日目の形をもう一度まとめます。
public class Profile {
String bio;
Profile(String bio) {
if (bio == null || bio.isEmpty()) {
this.bio = "よろしくお願いします。";
} else {
this.bio = bio;
}
}
void show() {
System.out.println("自己紹介: " + bio);
}
}
Javapublic class User {
String name;
int age;
Profile profile;
User(String name, int age, String bio) {
if (name == null || name.isEmpty()) {
System.out.println("名前が空です。'不明' にします。");
this.name = "不明";
} else {
this.name = name;
}
if (age < 0) {
System.out.println("年齢がマイナスです。0 にします。");
this.age = 0;
} else {
this.age = age;
}
this.profile = new Profile(bio);
}
void show() {
System.out.println("名前: " + name + ", 年齢: " + age);
profile.show();
}
}
Javapublic class Main {
public static void main(String[] args) {
User u1 = new User("太郎", 20, "Java 勉強中です!");
User u2 = new User("", -5, "");
u1.show();
System.out.println("-----");
u2.show();
}
}
Javaこのコードを見て、
「new した瞬間に、どんな状態のオブジェクトが生まれるか」を
自分の言葉で説明できたら、3日目はバッチリです。
3日目で絶対に押さえてほしい本質
今日いちばん大事なのは、
「初期化=ただ代入すること」ではなく、
“意味のある状態を保証すること”だと理解できたかどうか です。
コンストラクタでやるべきことは、
必須の情報を必ず受け取るようにする
おかしな値が来たら、そこでチェックして補正する
必要な他のオブジェクトも一緒に new しておく
そして、
new した瞬間に、もう安心して使える状態にしておく
この感覚が入っていれば、
コンストラクタはもう「文法」ではなく「設計の道具」になります。
4日目以降は、
この初期化の考え方を、もっと大きなクラス構成や、
設定クラス・ゲームのステータス・アプリの設定などに広げていくと、
一気に「現場で通用するコンストラクタの使い方」に近づいていきます。


