Java超|オブジェクト生成とコンストラクタの関係

戦士は生まれた瞬間に、最初の状態が整えられる。コンストラクタが分かると、オブジェクト生成の流れがぐっと見やすくなります。

これまで、クラスの中にはフィールドやメソッドを用意できることを学んできました。

フィールドは、オブジェクトが持つ情報です。
メソッドは、オブジェクトが行う処理です。

ドラゴンボールの世界観でたとえると、サイヤ人戦士という設計図の中に、戦闘力や気の量といった情報を持たせ、状態を表示する動きも用意しておくようなものです。

ただ、実際にオブジェクトを作るときには、ひとつ大切なことがあります。

それは、作られた直後のオブジェクトがどんな状態になっているのか、という点です。

何も初期設定されていないままだと、その戦士がどんな状態で登場したのかが分かりにくくなります。

そこで使うのが、コンストラクタです。

コンストラクタは、オブジェクトが作られた瞬間に自動で動く特別なしくみです。

ドラゴンボールでたとえると、新しい戦士が登場した瞬間に、戦闘力や気の量の初期値を整え、登場の合図を出すような処理です。

コンストラクタを理解すると、オブジェクト生成と初期化が、実はひとつの流れとしてつながっていることが見えてきます。

コンストラクタはオブジェクト作成時に自動で動く

コンストラクタは、クラスの中に書く特別な処理です。

見た目はメソッドに少し似ています。
でも、役割はメソッドとははっきり違います。

いちばん大きな特徴は、オブジェクトが作成されたときに自動で実行されることです。

普通のメソッドは、必要なときに自分で呼び出します。

たとえば、状態を表示したいときは、次のように show() を呼び出します。

goku.show();

これは、自分で呼び出している処理です。

一方で、コンストラクタは次のように new を使ってオブジェクトを作ったときに、自動で実行されます。

Saiyan goku = new Saiyan();

この1行で、Saiyan オブジェクトが作られます。
そして、その瞬間に Saiyan クラスのコンストラクタが動きます。

ドラゴンボールでたとえると、新しい戦士が修行場や戦場に現れた瞬間、最初の戦闘力や気の量を整える準備処理が自動で行われるようなものです。

ドラゴンボールでたとえると、登場時の初期設定

コンストラクタは、戦士が生まれた瞬間の初期設定だと考えると、とても分かりやすいです。

たとえば、新しい戦士を1人作ったとします。

そのとき、何も決まっていない状態では困ります。

戦闘力は最初に 0 にしておく。
気の量は最初に 0.0 にしておく。
戦士を作成しました、と表示して登場を知らせる。

こうした処理を、オブジェクト作成時に自動で行えるのがコンストラクタです。

Javaのしくみドラゴンボールでたとえると
クラスサイヤ人戦士の設計図
オブジェクト生成新しい戦士が登場する
コンストラクタ登場時に初期状態を整える処理
初期化戦闘力や気の量を最初の値にする

コンストラクタは、あとから任意に使う技というより、戦士が登場した瞬間に必ず発動する準備処理です。

この感覚を持つと、メソッドとの違いも見えやすくなります。

図:コンストラクタの自動実行

この図が示していること

この図は、Saiyan クラスという設計図から、new Saiyan() によって goku オブジェクトが作られる流れを表しています。

このとき、オブジェクトが作られるだけではなく、Saiyan() というコンストラクタも自動で実行されます。
その結果、goku オブジェクトは power = 0、kiEnergy = 0.0 という初期値を持った状態で完成します。

ここで大切なのは、コンストラクタはあとから手動で使う処理ではなく、オブジェクト生成とセットで働く初期化のしくみだということです。

コンストラクタはメソッドに似ているけれど別物

コンストラクタは、見た目がメソッドに少し似ています。

しかし、次の2つが大きく違います。

1つ目は、名前が必ずクラス名と同じであることです。
2つ目は、戻り値の型を書かないことです。

たとえば、Saiyan クラスのコンストラクタなら、名前も Saiyan になります。

public Saiyan()
{
    power = 0;
    kiEnergy = 0.0;
    System.out.println("戦士を作成しました。");}

ここで注目するところは、次の2つです。

注目点内容
名前クラス名と同じ Saiyan
戻り値void も int も String も書かない

普通のメソッドなら、戻り値がない場合は void を書きます。

public void show()

しかし、コンストラクタには void を書きません。

ここを間違えて public void Saiyan() のように書くと、それはコンストラクタではなく、Saiyan という名前の普通のメソッドとして扱われてしまいます。

項目メソッドコンストラクタ
名前自由につけられるクラス名と同じ
戻り値void や int などを書く書かない
実行タイミング呼び出したときnew で作成したときに自動
主な役割必要な処理を行う作成直後の初期設定を行う

この違いを押さえておくと、コンストラクタをメソッドと混同しにくくなります。

コンストラクタの役割は初期化

コンストラクタの主な役割は、初期化です。

初期化とは、オブジェクトが作られた直後に、最初の状態を整えることです。

たとえば、Saiyan クラスなら、次のような初期設定が考えられます。

初期化するもの初期値意味
power0戦闘力の初期値
kiEnergy0.0気の量の初期値

ドラゴンボールでたとえると、戦士が登場した直後に、まだ本格的な戦闘に入る前の基本状態を整えておくようなものです。

何も決まっていない戦士ではなく、最低限の状態を持った戦士として生まれる。
これがコンストラクタの大切な役割です。

さらに、初期化だけでなく、登場メッセージのような処理も書けます。

System.out.println("戦士を作成しました。");

このように、コンストラクタには「オブジェクトを作った瞬間に行いたい処理」をまとめて書けます。

コンストラクタの動きを確認する

実際のプログラムで、コンストラクタの動きを確認していきましょう。

ファイル名:Sample4.java

class Saiyan
{
    private int power;
    private double kiEnergy;

    public Saiyan()
    {
        power = 0;
        kiEnergy = 0.0;
        System.out.println("戦士を作成しました。");
    }

    public void show()
    {
        System.out.println("戦闘力は" + power + "です。");
        System.out.println("気の量は" + kiEnergy + "です。");
    }
}

class Sample4
{
    public static void main(String[] args)
    {
        Saiyan goku = new Saiyan();
        goku.show();
    }
}

このプログラムでは、Saiyan クラスの中にコンストラクタがあります。

public Saiyan()
{
    power = 0;
    kiEnergy = 0.0;
    System.out.println("戦士を作成しました。");
}

この部分がコンストラクタです。

名前は Saiyan です。
クラス名と同じです。
戻り値の型は書かれていません。

new と一緒にコンストラクタが動く

main メソッドの中では、次の1行でオブジェクトを作っています。

Saiyan goku = new Saiyan();

この1行では、いくつかのことが連続して起きています。

順番起きていること
1Saiyan クラスをもとにオブジェクトを作る
2new Saiyan() によってコンストラクタが自動で実行される
3power に 0 が入る
4kiEnergy に 0.0 が入る
5戦士を作成しました。 と表示される
6作られたオブジェクトを goku で扱えるようになる

ここで大切なのは、コンストラクタを別の行で呼び出していないことです。

たとえば、次のように書いているわけではありません。

goku.Saiyan();

コンストラクタは、new Saiyan() と書いた時点で自動的に動きます。

ドラゴンボールでたとえると、戦士が登場する瞬間に、初期状態を整える儀式が自動で発動するようなものです。

show() を呼ぶと初期化された値が見える

オブジェクトを作ったあと、次のように show() を呼び出しています。

goku.show();

show() は普通のメソッドです。

public void show()
{
    System.out.println("戦闘力は" + power + "です。");
    System.out.println("気の量は" + kiEnergy + "です。");
}

このメソッドは、現在の power と kiEnergy を表示します。

コンストラクタで次のように初期化しているため、

power = 0;
kiEnergy = 0.0;

show() を呼ぶと、初期化された値が表示されます。

実行結果は次のようになります。

戦士を作成しました。
戦闘力は0です。
気の量は0.0です。

この結果から、次の流れが分かります。

表示どこで起きたか
戦士を作成しました。コンストラクタ
戦闘力は0です。show() メソッド
気の量は0.0です。show() メソッド

つまり、オブジェクトを作ったときにコンストラクタが先に動き、そのあとで show() が呼ばれています。

図:コンストラクタが自動で初期化を行う

この図が示していること

この図は、new Saiyan() によってオブジェクトが作られる瞬間に、コンストラクタ public Saiyan() が自動で実行される流れを表しています。

コンストラクタの中で power は 0、kiEnergy は 0.0 に設定されます。
その結果、右側の goku オブジェクトは、初期値を持った状態で完成します。

ここで大切なのは、コンストラクタはあとから手動で呼ぶ処理ではなく、オブジェクト生成とセットで動く初期化処理だということです。

コンストラクタは自分で自由に呼び出すものではない

メソッドは、自分で好きなタイミングに呼び出せます。

たとえば、show() は次のように呼び出します。

goku.show();

必要なときに何度でも呼び出せます。

しかし、コンストラクタはそのように使うものではありません。

コンストラクタは、new によってオブジェクトを作るときに自動で動きます。

種類呼び出し方タイミング
コンストラクタnew Saiyan() と一緒に動くオブジェクト作成時
メソッドgoku.show() のように呼ぶ必要なとき

そのため、コンストラクタの中には、オブジェクトが最初に持つべき状態を書きます。

今回なら、戦闘力を 0 にする、気の量を 0.0 にする、という処理が自然です。

ドラゴンボールでたとえると、戦士が登場した瞬間にだけ行う初期準備です。
戦闘中に何度も自由に使う通常の技とは、役割が違います。

フィールドにはもともと初期値がある

ここで、フィールドの初期値についても整理しておきましょう。

Javaでは、フィールドには型に応じた初期値が自動で入ります。

初期値
booleanfalse
char\u0000
整数型0
浮動小数点型0.0
参照型null

今回の Saiyan クラスでは、フィールドに int と double を使っています。

private int power;
private double kiEnergy;

int 型の power は、何もしなくても初期値として 0 を持ちます。
double 型の kiEnergy は、何もしなくても初期値として 0.0 を持ちます。

では、コンストラクタでわざわざ次のように書く意味がないのかというと、そうではありません。

power = 0;
kiEnergy = 0.0;

コンストラクタに書くことで、初期化の意図がはっきりします。

このクラスでは、作成時に戦闘力を 0、気の量を 0.0 にするのだと、コードを読む人に伝わります。

また、今回のようにメッセージを表示する処理も一緒に書けます。

System.out.println("戦士を作成しました。");

つまり、自動初期値があることと、コンストラクタで初期化を書くことは、少し役割が違います。

自動初期値コンストラクタでの初期化
Javaが型に応じて自動で入れる作成者が意図を持って初期状態を決める
最低限の初期状態明示的な初期設定
メッセージなどの処理はできない初期化以外の処理も書ける

コンストラクタは作られた直後の状態を保証しやすい

コンストラクタの大きな価値は、オブジェクトが作られた直後の状態を整えやすいことです。

コンストラクタがなければ、オブジェクトを作ったあとに必要な設定を手動で行う必要があります。

すると、次のような問題が起きるかもしれません。

起こりうる問題内容
設定し忘れ戦闘力や気の量を設定し忘れる
状態があいまい作った直後の値が分かりにくい
処理が散らばる初期設定がいろいろな場所に分かれる
読みにくいどこで初期状態が決まるのか追いにくい

コンストラクタを使えば、オブジェクトを作った瞬間に初期化処理が必ず実行されます。

ドラゴンボールでたとえると、新しい戦士が登場するときに、最低限の身支度や状態確認が必ず行われるようなものです。

この「作られた直後の安心感」を作れることが、コンストラクタの強みです。

メソッドとの役割の違いを整理する

ここで、コンストラクタとメソッドの違いをもう一度整理しておきます。

項目コンストラクタメソッド
主な役割作成時の初期化必要な処理の実行
名前クラス名と同じ自由につけられる
戻り値書かないvoid や int などを書く
実行タイミングnew と一緒に自動呼び出したとき
Saiyan()show()

Sample4.java では、次のように考えます。

コード種類役割
public Saiyan()コンストラクタ作成時に戦闘力と気の量を初期化する
public void show()メソッド現在の状態を表示する

Saiyan() は、オブジェクトを作るときに自動で動きます。
show() は、オブジェクトを作ったあと、必要なタイミングで呼び出します。

この違いが分かると、クラスの中で何をコンストラクタに書き、何をメソッドに書くべきかが見えやすくなります。

図:コンストラクタとメソッドの違い

この図が示していること

この図は、コンストラクタとメソッドの違いを比較しています。

コンストラクタはクラス名と同じ名前で、戻り値を書きません。
そして、new でオブジェクトを作ったときに自動で実行されます。

一方、メソッドは自由な名前をつけられ、void などの戻り値の型を書きます。
そして、必要なタイミングで自分で呼び出します。

ここから分かるのは、コンストラクタは作成時の初期化、メソッドは必要な処理の実行というように、役割が分かれていることです。

コンストラクタを学ぶと次の内容が理解しやすくなる

コンストラクタの基本が分かると、この先に出てくる内容も理解しやすくなります。

特に、次のような内容につながります。

次に学ぶ内容コンストラクタとのつながり
引数つきコンストラクタ作成時に値を渡して初期化する
thisフィールドと引数を区別するときに使う
カプセル化初期状態を安全に整える設計につながる
オブジェクトの状態管理作成直後の状態をはっきりさせる

今回の Sample4.java では、引数のないコンストラクタを使いました。

public Saiyan()

この形では、いつも同じ初期値でオブジェクトが作られます。

次の段階では、オブジェクトを作るときに名前や戦闘力を渡して、最初から具体的な値を持たせる形も学べます。

ドラゴンボールでたとえると、今回は「戦士を作ったら戦闘力0、気の量0.0で登場する」という基本形です。
次は「戦士を作るときに、名前や初期戦闘力も一緒に登録する」という形へ進んでいくイメージです。

いちばん大事な感覚

オブジェクト生成とコンストラクタの関係で大切なのは、次の感覚です。

ポイント内容
コンストラクタクラスの中に書く特別な処理
名前クラス名と同じ
戻り値書かない
実行タイミングnew でオブジェクトを作ったときに自動実行
主な役割フィールドの初期化など、作成直後の準備
メソッドとの違いメソッドは必要なときに自分で呼び出す

ドラゴンボールでたとえると、コンストラクタは戦士が登場した瞬間に発動する初期準備です。

戦闘力を整える。
気の量を整える。
登場したことを知らせる。

こうした処理を、オブジェクト生成時に自動で行ってくれます。

この感覚がつかめると、コンストラクタはただの特別な文法ではなく、オブジェクトを正しい状態で生み出すための大切なしくみとして見えてきます。