Java入門|オブジェクト作成時に動くコンストラクタのしくみ

戦士は作られた瞬間に動き出す。コンストラクタがわかると、初期設定の意味がはっきり見えてくる

これまでの学習で、クラスの中にはフィールドやメソッドを用意できること、そしてオブジェクトを作ってから値を設定し、必要な処理を呼び出せることを学んできました。ここまででも、クラスを使ったプログラムの流れはかなり見えてきています。ですが、実際のプログラムでは、オブジェクトが作られた直後に、ある程度の初期設定を自動でしておきたい場面がよくあります。そうしないと、作ったばかりのオブジェクトがどんな状態なのかがあいまいになってしまうからです。

ドラゴンボールで考えるなら、戦士が登場した瞬間に、最初の状態がきちんと整っていてほしいですよね。たとえば、まだ名前や戦闘力を細かく設定していない段階でも、とりあえず初期状態として戦闘力は 0、気の量は 0.0 にしておく、あるいは「戦士を作成しました」と表示して登場の合図を出す、といったことです。こうした「オブジェクトが作られた瞬間に自動で行う処理」をまとめておけるのがコンストラクタです。ここでは、そのコンストラクタの基本を、ドラゴンボールのたとえでやさしく整理していきます。

コンストラクタは、オブジェクト作成時に自動で動く特別なしくみ

コンストラクタは、クラスの中に書く特別な処理です。
見た目はメソッドに少し似ていますが、役割ははっきり違います。

いちばん大事なのは、コンストラクタは

オブジェクトが作成されたときに、自動で実行される

という点です。

メソッドの場合は、自分で

goku.show();

のように呼び出して使いました。
でもコンストラクタは、自分で好きなタイミングに呼ぶものではありません。

new Saiyan()

と書いてオブジェクトを作ったときに、その瞬間、自動的に動きます。

この「作成時に自動で動く」という性質が、コンストラクタのいちばんの特徴です。

ドラゴンボールで考えるコンストラクタの感覚

ドラゴンボールで考えると、コンストラクタは「戦士が登場した直後の初期設定」を自動で行う仕組みだと思うとわかりやすいです。

たとえば新しくサイヤ人の戦士を1人作るとします。
そのときに、何も決めないまま放り出すのではなく、

  • 戦闘力を 0 にしておく
  • 気の量を 0.0 にしておく
  • 登場メッセージを出す

といった初期状態を、自動的に整えておきたいわけです。

つまりコンストラクタは、

戦士が生まれた瞬間に行う準備処理

のようなものです。

この感覚で見ると、コンストラクタは「あとから使う技」ではなく、「登場時に必ず発動する初期化の技」だと考えられます。

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

コンストラクタは見た目がメソッドによく似ています。
ですが、大事な違いが2つあります。

1つ目は、名前が必ずクラス名と同じであることです。
たとえばクラス名が Saiyan なら、コンストラクタ名も Saiyan です。

2つ目は、戻り値を書かないことです。
メソッドなら void や int のような戻り値の型を書きましたが、コンストラクタにはそれがありません。

たとえば、次のような形になります。

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

ここでは

  • 名前が Saiyan
  • 戻り値の型が書かれていない

という点が、コンストラクタらしい書き方です。

表で整理するとこうです。

項目メソッドコンストラクタ
名前自由につけるクラス名と同じ
戻り値必要書かない
実行されるタイミング呼び出したときオブジェクト作成時に自動

この違いが見えるようになると、メソッドとコンストラクタを区別しやすくなります。

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

コンストラクタの役割をひとことで言うと、初期化です。

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

たとえば Saiyan クラスなら、

  • 戦闘力の初期値を決める
  • 気の量の初期値を決める
  • 登場メッセージを表示する

といった処理をまとめておくことができます。

ドラゴンボールで言えば、「まだ本格的に戦闘準備はしていないが、登場時の基本状態だけはそろえておく」という感じです。

この初期化をコンストラクタにまとめておけば、オブジェクトを作るたびに毎回同じ準備を自動でしてくれるので、とても便利です。

実際のプログラムで見てみる

では、ドラゴンボールのたとえに合わせて、サンプルプログラムを見てみましょう。

ファイル名:Sample4.java

class Saiyan
{
    private int power;
    private double energy;

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

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

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

このプログラムの流れはとても大切です。

まず Saiyan クラスの中に、コンストラクタが定義されています。

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

この処理は、オブジェクト作成時に自動で動きます。

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

main メソッドでは次の1行があります。

Saiyan goku = new Saiyan();

ここで行われていることは、見た目以上に大事です。

この1行で、

  1. Saiyan オブジェクトを作る
  2. その瞬間にコンストラクタが自動で呼ばれる
  3. power と energy が初期化される
  4. 「戦士を作成しました。」が表示される

という流れが起こります。

つまり、コンストラクタは別に書いて呼び出しているのではなく、new によるオブジェクト作成とセットで動いているのです。

ここが、メソッドとの大きな違いです。

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

そのあとで、

goku.show();

を呼び出しています。

show() の中では power と energy を表示するので、実行結果は次のようになります。

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

この結果からわかるのは、

  • オブジェクト作成時にコンストラクタが動いた
  • その中で power が 0、energy が 0.0 に設定された
  • だから show() で表示したときに、その値が見えている

ということです。

つまり、コンストラクタは「ただメッセージを出す」だけではなく、オブジェクトの中身を最初に整えているわけです。

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

メソッドは必要なときに自分で呼び出しました。
でもコンストラクタはそうではありません。

コンストラクタは、

  • 自分で好きなタイミングに使うものではない
  • オブジェクト作成のときだけ自動で動く

という点が大切です。

だから、コンストラクタの中には「そのオブジェクトが最初に持つべき状態」を書くのが自然です。

たとえば今回なら、

  • power を 0 にする
  • energy を 0.0 にする

という初期化がぴったりです。

ドラゴンボールで言えば、戦士の登場時設定を行う場所だと考えると、役割がはっきり見えてきます。

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

ここで少し整理しておきたいのが、フィールドには、コンストラクタで値を入れなくても、型に応じた初期値が入るということです。

Javaでは、フィールドは自動的に次のような初期値を持ちます。

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

だから今回の Saiyan クラスでも、実は power は 0、energy は 0.0 が最初から入ります。

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

  • 初期化の意図がはっきりする
  • 初期設定をまとめて管理しやすい
  • メッセージ表示などの追加処理も書ける

というよさがあります。

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

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

コンストラクタの大きな価値は、オブジェクトが作られた瞬間に、ある程度まともな状態になっていることを保証しやすい点です。

たとえばコンストラクタがなければ、オブジェクトを作ったあとに

  • 戦闘力を設定し忘れる
  • 気の量を設定し忘れる
  • 初期表示を忘れる

といったことが起きやすくなります。

でもコンストラクタがあれば、作られた瞬間に必要な初期処理が必ず実行されます。

ドラゴンボールで言えば、戦士が現れたときに最低限の装備や初期状態が必ず整っているイメージです。
この「最初の安心感」を作れることが、コンストラクタの強みです。

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

ここで、コンストラクタとメソッドの役割をあらためて整理しておきましょう。

項目コンストラクタメソッド
役割作成時の初期化必要な機能を実行
名前クラス名と同じ自由につける
戻り値なしあり/なしを選べる
呼び出しnew と一緒に自動自分で呼び出す

今回のサンプルで言えば、

  • Saiyan() がコンストラクタ
  • show() がメソッド

です。

Saiyan() は作成時に必ず動き、show() はあとから必要に応じて呼び出します。
この区別ができるようになると、クラスの中の役割分担がかなり見えやすくなります。

図で見ると流れがわかりやすい

この図では、左側の new Saiyan() から中央のコンストラクタへ流れが伸びています。
これによって、オブジェクト作成とコンストラクタ実行がひと続きの動作だとわかります。

中央のコンストラクタ箱には、power や energy の初期化処理と、作成メッセージの表示がまとめられています。
つまり、ここが「作られた瞬間の準備」をする場所です。

右側の goku オブジェクトを見ると、初期値が入った状態で完成していることがわかります。
そして下部の show() の結果を見ることで、その初期化された値がそのまま利用されていることも確認できます。

いちばん大事な感覚

「オブジェクト作成時に動くコンストラクタのしくみ」で大切なのは、次の感覚です。

  • コンストラクタはクラスの中に書く特別な処理
  • 名前はクラス名と同じで、戻り値は書かない
  • オブジェクトを作成するときに自動で実行される
  • 主な役割は、フィールドの初期化などの初期設定
  • メソッドとは違って、自分で自由に呼び出すものではない

ドラゴンボールで言いかえるなら、

  • 戦士が登場した瞬間に
  • 初期状態を整え
  • 必要な登場処理を自動で行う仕組み

ということです。

この感覚がつかめると、コンストラクタは「特別な書き方」ではなく、オブジェクトを正しく生み出すための準備装置として見えてきます。ここがわかると、この先に出てくる引数つきコンストラクタや this の使い方も、ぐっと理解しやすくなります。