コンストラクタ¶
~コンストラクタで「初期状態」を用意しよう~
1. フィールドに値を後から設定するのは面倒?¶
前の章では、クラスからインスタンス(実体)を作ったあとに、フィールド(変数)に値を手動で設定していました。たとえば、次のようなコードでした:
Pen myPen = new Pen(); // Penのインスタンスを作成
myPen.color = "青"; // 色を手動で設定
myPen.hasCap = true; // キャップがあることを手動で設定
このやり方でも問題なく動きますが、次のような不便さがあります。
■ 毎回同じ値なら、設定が面倒!
たとえば、「色はいつも黒」「キャップは常についている」というペンを作るとします。 毎回同じように書くのは、ちょっと無駄が多いですよね。
Pen pen1 = new Pen();
pen1.color = "黒";
pen1.hasCap = true;
Pen pen2 = new Pen();
pen2.color = "黒";
pen2.hasCap = true;
// … これが何本も続く
■ ミスの原因にもなる
手動で設定するということは、「うっかり忘れる」「値を間違える」可能性もあります。
Pen pen3 = new Pen();
// pen3.color = "黒"; ← 書き忘れたらどうなる?
pen3.write(); // 何色のペンか分からない!
■ だから、最初からセットできたら楽!
こんなときに便利なのが「コンストラクタ」です。 コンストラクタを使えば、インスタンスを作った瞬間に初期値を自動で設定できます。
これにより、
- コードが短く、分かりやすくなる
- 設定漏れのリスクが減る
- 一貫性のある状態でスタートできる
といったメリットが得られます。
2. コンストラクタってどう書くの?¶
■ まずは役割の再確認
コンストラクタは、「クラスからインスタンスを作るときに最初に一度だけ実行される特別なメソッド」です。 目的は、インスタンスの初期状態を設定することです。
Pen myPen = new Pen();
上のように new Pen(); と書くと、自動的に Penクラスのコンストラクタが呼び出されます。
■ 書き方の基本(シグネチャ)
コンストラクタには、いくつかのルールがあります。
public Pen() {
// コンストラクタの本体(ここに初期値の設定を書く)
}
要素 | 意味 |
---|---|
public |
どこからでも呼び出せるようにするアクセス修飾子 |
Pen |
クラス名と全く同じ名前にする必要がある |
() |
引数がないことを示す(後で引数付きも学びます) |
{ ... } |
処理を各ブロック |
🚫 こう書くと「コンストラクタ」じゃなくなる!
public void Pen() {
// これはメソッド扱いで、コンストラクタではありません!
}
戻り値(voidなど)をつけてしまうと、それは通常のメソッドになってしまいます。 コンストラクタには戻り値を書いてはいけません。
■ 初期値の設定方法
次に、コンストラクタの中でフィールドに値を設定する方法を見てみましょう。
public Pen() {
color = "黒";
hasCap = true;
}
このように直接フィールドに値を代入するだけでOKです。
■ でも「this.」ってなに?
次のような書き方もよく見かけます:
public Pen() {
this.color = "黒";
this.hasCap = true;
}
ここで使われている this は、「このインスタンス自身」を指します。
どちらでも動きますが、
- 変数名が曖昧になる場合(引数とフィールドが同じ名前など)には this を使うのが必須
- 明示的に書いたほうがコードが読みやすいというメリットもあります
したがって、初心者でも this を使う習慣をつけておくのがおすすめです。
■ まとめ表
項目 | 説明 |
---|---|
コンストラクタ | インスタンスを作ること子に最初に実行される特別なメソッド |
シグネチャ | public クラス名() のように、戻り値を書かず、クラス名と一致させる |
処理内容 | フィールドに初期値を代入するコードを書く |
thisの意味 | 「このオブジェクト自身」を指す・フィールドへの代入に使える |
3. 実際にコンストラクタを使ってみよう¶
■ これまでのコード(おさらい)
前章では、Pen クラスのインスタンスを作ってから、後からフィールドに値を設定していました。
public class Pen {
String color;
boolean hasCap;
public void write() {
System.out.println("書いています...");
}
}
public class Main {
public static void main(String[] args) {
Pen myPen = new Pen(); // インスタンスの作成
myPen.color = "青"; // 後から値を設定
myPen.hasCap = true;
myPen.write();
}
}
このように毎回同じ値を設定するのは面倒ですし、書き忘れによるバグの元にもなります。
■ コンストラクタを追加してみよう!
では、Pen クラスにコンストラクタを追加して、初期状態を自動でセットしてみましょう。
✅ 修正後の Pen クラス
public class Pen {
String color;
boolean hasCap;
// コンストラクタの定義
public Pen() {
this.color = "黒";
this.hasCap = true;
}
public void write() {
System.out.println("書いています...");
}
}
このように書くと、new Pen(); をした時点で、自動的に以下の状態になります:
- 色 → 「黒」
- キャップ → 「ある(true)」
■ Mainクラスでの使い方は変わらない
public class Main {
public static void main(String[] args) {
Pen myPen = new Pen(); // ここでコンストラクタが自動実行される
myPen.write(); // フィールドに値が入っている状態でメソッドを使える
}
}
ポイントは、「呼び出し側は書く内容が減ってシンプルになる」ということです。
■ 実行結果
書いています...
目立った変化は出力上はありませんが、コードの中では自動的に color と hasCap がセットされており、より安全でミスの少ないコードになっています。
■ 補足:複数のインスタンスを作ってみよう
Pen pen1 = new Pen();
Pen pen2 = new Pen();
System.out.println(pen1.color); // 黒
System.out.println(pen2.color); // 黒
pen1.color = "赤"; // pen1 だけ変更
System.out.println(pen1.color); // 赤
System.out.println(pen2.color); // 黒(影響を受けない!)
→ このように、インスタンスごとに状態が独立していることも確認できます。
■ まとめ表
項目 | 説明 |
---|---|
コンストラクタの役割 | インスタンスの初期状態を設定する |
書き方 | public クラス名() {...} ※戻り値は書かない |
this の使い方 | フィールドに値を代入する際によく使う |
メリット | 値の設定漏れを防ぎ、コードがスッキリする |
複数インスタンスの確認 | インスタンスごとに状態は独立している |
4. コンストラクタって特別なの?JVMのしくみをのぞいてみよう¶
■ そもそも「コンストラクタ」って何が特別なの?
Javaでは、クラスからオブジェクトを作るとき、必ず「コンストラクタ」が呼ばれます。
Pen myPen = new Pen(); // ← ここで new Pen() がコンストラクタの呼び出し
このとき、Javaのプログラムを動かしている「JVM(Java Virtual Machine)」が、水面下でいろいろな処理をしてくれています。
■ JVM のイメージ図:オブジェクトを作るしくみ
次のようなステップで、JVMはオブジェクトを作成しています。
Step 1: Penクラスの定義をもとに、メモリを確保(箱を作る)
Step 2: フィールドを初期化(デフォルト値:nullやfalse)
Step 3: コンストラクタを呼び出して、初期状態を上書き
Step 4: myPen にその「箱」のアドレスを代入
たとえるなら…
- Penクラスは「設計図」、
- JVMは「工場」、
- new Pen()は「工場に製造を依頼」しているイメージです。
■ なぜ「戻り値なし」なのに使えるの?
通常のメソッドは戻り値の型を書く必要がありますが、コンストラクタにはありません。
public Pen() { // ← 戻り値の型がない!(これが正しい書き方)
this.color = "黒";
this.hasCap = true;
}
- なぜか?
- Javaでは、new を使うと、自動的に「コンストラクタの呼び出し → メモリ確保 → 参照を返す」まで含まれているからです。
■ 「シグネチャ」が大事:コンストラクタの見分けポイント
要素 | 内容 |
---|---|
メソッド名 | クラス名と同じである必要がある |
戻り値 | 書いてはいけない(書くと普通のメソッドになってしまう) |
public |
通常はpublicにしておく(外から呼べるように) |
例:正しいコンストラクタ
public class Pen {
String color;
boolean hasCap;
// 正しいコンストラクタ
public Pen() {
this.color = "黒";
this.hasCap = true;
}
}
× 間違った例:
// これはコンストラクタではなく、普通のメソッド
public void Pen() {
this.color = "黒";
this.hasCap = true;
}
→ void
を書いた時点で「ただのメソッド」になります。
■ なぜ this. を使うの?
this は「このインスタンス自身のフィールド」という意味です。たとえば:
this.color = "黒";
これは、「このオブジェクトが持つ color に “黒” を代入せよ」という指示です。 フィールドとローカル変数が同じ名前のときに使うことで、あいまいさをなくすためにも役立ちます。
■ 補足:デフォルトコンストラクタってなに?
もし自分でコンストラクタを1つも定義していない場合、Javaは自動的に「中身が空のコンストラクタ」を用意してくれます。
// 自分で何も書かなくても…
Pen myPen = new Pen(); // ← 動く
// ただし、一度でも自作コンストラクタを定義すると、自動ではつかなくなる!
■ まとめ表
項目 | 説明 |
---|---|
コンストラクタの役割 | オブジェクト生成時に初期値を設定する特別なメソッド |
書き方 | うラス名と同じ、戻り値なし |
呼ばれるタイミング | new と同時に自動的に呼び出される |
JVMでの流れ | メモリ確保 -> フィールド初期化 -> コンストラクタ実行 |
注意点 | void を書いたらただのメソッドになるのでNG |
このように、コンストラクタは「オブジェクトができる瞬間に一度だけ呼ばれる特別な処理」です。
5. 引数つきコンストラクタで自由に初期化しよう¶
■ こんなときに便利!
前のセクションでは、コンストラクタで「いつも同じ初期値(色=黒、キャップあり)」をセットしていました。
でも、現実のペンは毎回同じとは限りません。
たとえば:
Pen bluePen = new Pen("青", true);
Pen redPen = new Pen("赤", false);
→ コンストラクタに「引数」をつければ、それが可能になります。
■ 引数つきコンストラクタの書き方
public class Pen {
String color;
boolean hasCap;
// 引数つきコンストラクタ
public Pen(String color, boolean hasCap) {
this.color = color; // 右側は引数、左側はフィールド
this.hasCap = hasCap;
}
public void write() {
System.out.println(color + "色のペンで書いています...");
}
}
public class Main {
public static void main(String[] args) {
Pen bluePen = new Pen("青", true);
Pen redPen = new Pen("赤", false);
bluePen.write(); // 青色のペンで書いています...
redPen.write(); // 赤色のペンで書いています...
}
}
■ なぜ this.color = color
のように書くの?
これは、引数の color と、フィールドの color の名前が同じだからです。
this.color
→ このオブジェクトが持っている変数color
→ コンストラクタの引数として渡された値
名前が同じときは、this.
をつけて「どっちなのか」を明確にする必要があります。
■ 引数があるコンストラクタ vs 引数がないコンストラクタ
2つ以上のコンストラクタを定義することもできます。これを オーバーロード(多重定義) といいます。
public class Pen {
String color;
boolean hasCap;
// 引数なし(デフォルト)のコンストラクタ
public Pen() {
this.color = "黒";
this.hasCap = true;
}
// 引数つきのコンストラクタ
public Pen(String color, boolean hasCap) {
this.color = color;
this.hasCap = hasCap;
}
}
Pen defaultPen = new Pen(); // 黒・キャップあり
Pen customPen = new Pen("緑", false); // 緑・キャップなし
→ 状況に応じて使い分けられる!
■ まとめ
項目 | 内容 |
---|---|
引数付きコンストラクタ | オブジェクトを作る時に、初期値を指定できる |
書き方 | クラスメイト同じ名前、パラメータを受け取る |
this の結果 |
フィールドの引数の区別を明確にするために使う |
オーバーロード | 引数の異なるコンストラクタを複数定義できる |
6. インスタンスはそれぞれ独立している¶
■ 同じ「Penクラス」から作っても、中身はそれぞれ違う!
クラスは設計図にすぎません。 それをもとに作られたインスタンスは、それぞれ別の「実体」です。
たとえば:
Pen penA = new Pen("青", true);
Pen penB = new Pen("赤", false);
この2つのオブジェクトは、色もキャップの有無も違う状態を持っています。
■ 実際に動かしてみよう
public class Pen {
String color;
boolean hasCap;
public Pen(String color, boolean hasCap) {
this.color = color;
this.hasCap = hasCap;
}
public void write() {
System.out.println(color + "色のペンで書いています...");
}
}
public class Main {
public static void main(String[] args) {
Pen penA = new Pen("青", true);
Pen penB = new Pen("赤", false);
penA.write(); // → 青色のペンで書いています...
penB.write(); // → 赤色のペンで書いています...
// penAの色を変更してもpenBには影響しない
penA.color = "緑";
penA.write(); // → 緑色のペンで書いています...
penB.write(); // → 赤色のペンで書いています...
}
}
→ penA と penB は完全に独立して動いています。 片方を変えても、もう片方には影響しません。
■ なぜ独立しているの?
Javaでは、new
を使ってインスタンスを生成すると、メモリ上に新しい領域が確保されます。
つまり、
penA
→ メモリ上の「箱A」penB
→ メモリ上の「箱B」
のように、別々の箱にそれぞれの値が入っていると考えるとイメージしやすいです。
■ 現実の比喩で考えてみよう
- クラス →「ペンの設計図」
- インスタンス →「実際に製造された個々のペン」
製造されたペンは、それぞれ色やキャップの有無が違ってもOK。 変更しても、他のペンには関係ありません。
■ まとめ
項目 | 内容 |
---|---|
インスタンスの独立性 | 同じクラスでも、作られたオブジェクトは別々の状態を持つ |
状態の違い | フィールドの値を変えても、他のインスタンスには影響なし |
メモリ上の独立性 | new で作るたびに、別々のメモリ領域が割り当てられる |
現実世界の例え | 同じ型番のペンでも、個体ごとに違いがあるのと同じ |
7. 練習問題¶
【問題1】クラスを作ってみよう
以下の仕様をもとに、「Book(本)」クラスを作成してください。
▼ クラス仕様:
- フィールド
title
(本のタイトル:文字列)author
(著者名:文字列)
- メソッド
introduce()
:タイトルと著者を紹介するメソッド
▼ 実装例(完成形イメージ):
Book book1 = new Book("走れメロス", "太宰治");
Book book2 = new Book("吾輩は猫である", "夏目漱石");
book1.introduce(); // → 「走れメロス」著:太宰治
book2.introduce(); // → 「吾輩は猫である」著:夏目漱石
【問題2】インスタンスを複数作って状態を確認しよう
- 上記の Book クラスを使って、3冊以上の本のインスタンスを作ってください。
- タイトルや著者をすべて異なる値にして、
introduce()
メソッドを呼び出して確認しましょう。 - どれか1冊のタイトルをあとから変更し、もう一度
introduce()
を呼んで違いを確認してみましょう。
book1.title = "新しいタイトル";
book1.introduce(); // 変更されたタイトルが表示されること
【問題3】独立性を確かめよう(応用)
- どの本のタイトルを変えても、他の本のタイトルには影響しないことを確認しましょう。
System.out.println(book2.title);
などで、他のインスタンスが変わっていないことを出力で確かめてください。
解答のヒント(構文テンプレートをクリックして表示)✍
public class Book {
String title;
String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
public void introduce() {
System.out.println("「" + title + "」著:" + author);
}
}
問題1から問題3までを実装した解答例をクリックして表示
まずはクラスの定義から。
// Book.java
public class Book {
String title; // 本のタイトル
String author; // 著者名
// コンストラクタ:タイトルと著者を受け取り、フィールドに設定
public Book(String title, String author) {
this.title = title;
this.author = author;
}
// 本の紹介を行うメソッド
public void introduce() {
System.out.println("「" + title + "」著:" + author);
}
}
そして、このクラスを使うメインクラス:
// Main.java
public class Main {
public static void main(String[] args) {
Book book1 = new Book("走れメロス", "太宰治");
Book book2 = new Book("吾輩は猫である", "夏目漱石");
Book book3 = new Book("羅生門", "芥川龍之介");
book1.introduce(); // → 「走れメロス」著:太宰治
book2.introduce(); // → 「吾輩は猫である」著:夏目漱石
book3.introduce(); // → 「羅生門」著:芥川龍之介
// book1のタイトルを変更
book1.title = "斜陽";
book1.introduce(); // → 「斜陽」著:太宰治
// book2の状態は変わらないことを確認
book2.introduce(); // → 「吾輩は猫である」著:夏目漱石
}
}
💡 解説
-
クラスとフィールド
-
title
とauthor
は本の情報(=状態)を表すフィールドです。 -
これらはインスタンスごとに異なる値を持ちます。
-
コンストラクタ
public Book(String title, String author) { this.title = title; this.author = author; }
-
Book
クラスのコンストラクタは、インスタンスを作るときに初期状態を設定するために使われます。 -
this.title
はフィールド、右側のtitle
は引数(外から受け取った値)です。 -
メソッド:
introduce
-
introduce()
は本の情報を出力するだけのシンプルなメソッドですが、オブジェクトの動作(ふるまい)を表現しています。 -
インスタンスの独立性
-
book1.title = "斜陽";
のように、1つのインスタンスの状態を変えても、他のインスタンス(book2
やbook3
)には影響がありません。 - これが「インスタンスはそれぞれ独立している」という考え方の確認です。