Javaのプログラム設計で「コンストラクタ」を使いたい方もいるでしょう。しかし、扱いが難しく、「上手く活用できていない」、「エラーが出る」などのケースも多々あります。
Javaでシステム全体やバックエンドを設計したい方にとっては、コンストラクタは大きなネックです。そこで本記事は、コンストラクタの書き方や細かなルール、使い方のバリエーションなどを紹介します。
目次
1.Javaの「コンストラクタ」をわかりやすく解説
Javaには、コンストラクタと呼ばれる特別なメソッドがあります。以下にコンストラクタの定義や目的を解説します。
コンストラクタとは
コンストラクタは、オブジェクト指向の特徴を持つJavaやPython、C++などのプログラミング言語で使われている特別なメソッドです。特別な理由は、クラス内にクラス名と同じ名前のメソッドを自動的に実行することにあります。
Javaのコンストラクタはなんのためにある?
Javaのコンストラクタには、オブジェクトを初期化する目的があります。初期化は、オブジェクトのフィールド変数(メンバ変数)を初期設定することです。初期設定とは、クラスの実行でオブジェクトからインスタンスが生成されるときに、初期値の取得やメモリ領域の確保などを行うことです。
内部で「new」して初期化されるときの流れ
通常、インスタンスの生成は「クラス名 変数名 = new クラス名()」で行われます。この「new」は「new演算子」のことで、新たなオブジェクトを作成するためのものです。new演算子を「new クラス名()」で記述すると、クラスに定義されたオブジェクトからインスタンスを作成します。
実行環境のシステム内部では、newによって新たなオブジェクト(インスタンス)のメモリ確保とデータ集合を作成し、それらがまとめてヒープ領域に確保される処置が進むのです。これを初期化する目的でコンストラクタが実行されています。
エンジニアにとっては、自動的に呼び出されるコンストラクタを使用することで、初期化を簡潔に行えるメリットがあります。
また、コンストラクタには、初期化以外に、引数としてデータを渡す役割もあります。そのため、intなどで数字を定義して変数に格納し、それをメインクラスのオブジェクトで使用することも可能です。
デフォルトコンストラクタと引数付きコンストラクタ
コンストラクタには、引数を持たずに実行される「デフォルトコンストラクタ」があります。コンストラクタを直接コードに記述しなくても、「デフォルトの引数なし」で実行されるコンストラクタのことです。
修飾子 クラス名(){ super(); } |
上記は、コンストラクタがなく、クラス内でデフォルトコンストラクタが暗黙的に実行されます。継承クラスではないにもかかわらず、コンパイルで自動的に「super();」が実行される理由は、Javaのクラスは最終的にすべて「Objectクラス」を継承しているためです。
ちなみに、デフォルトコンストラクタの逆は「引数付きコンストラクタ」です。引数付きではクラス内でコンストラクタを省略できません。そのため、コンストラクタを明示的に定義する必要があります。
2.Javaのコンストラクタの基本的な書き方の手順
Javaのコンストラクタを記述する方法について以下に解説します。
Javaのコンストラクタを宣言する
まずは、コンストラクタを宣言する必要があります。そのためには、「class クラス名{}」でコンストラクタを定義できるクラスを作成して宣言することです。
コンストラクタの例で「ConstructorExample」をクラス名にします。クラス名についてここであえて挙げたのは、コンストラクタではクラス名が重要だからです。
class ConstructorExample { } |
Javaのコンストラクタを初期化する
Javaのコンストラクタは、コンストラクタに何の値を設定するか、初期化によって設定を行います。その際に、クラス内に同名のメソッド「クラス名() {}」を置きます。これがコンストラクタです。
今回は、クラス名と同じ「ConstructorExample」です。これを初期化するには、「ConstructorExample(){}」のコンストラクタ本体内に初期化に必要な処理を記述することです。今回はシンプルに、「System.out.println()」の出力方法のみ内側に記述します。
class ConstructorExample { ConstructorExample(){ System.out.println("コンストラクタが実行されました"); } } |
メインなどでインスタンス化して呼び出す場合に、このコード文を別のクラスに加えてコンストラクタとなります。
Javaのコンストラクタを呼び出して実行する準備
上記だけでは、コンストラクタの宣言と初期化だけで、実行はできません。まずは最初の実行起点となる「public static void main」を記述したメインクラスを用意します。
そこでインスタンス生成に必要な「new演算子」で新たなオブジェクトを作成します。
public class Main { public static void main(String[] args) { ConstructorExample example = new ConstructorExample(); } } |
今回は、「new ConstructorExample()」と置いています。上記だけを使っても、実行はできないため、宣言と初期化を合わせて1まとまりのソースコードとします。
コンストラクタを実行できる完成のソースコード例
下記は、コンストラクタの作成手順と実行を確認するための完成したソースコード例です。
class ConstructorExample { ConstructorExample() { System.out.println("コンストラクタが実行されました"); } }
public static void main(String[] args) { ConstructorExample example = new ConstructorExample(); } } |
このソースコードを実行すると、「main」メソッドのインスタンス生成時に、メモリに読み込み済みの「ConstructorExample」クラスからコンストラクタ本体(ConstructorExample() )がメソッドとして呼び出され、初期化のために自動的に実行されます。
関連記事
Javaプログラミングで何ができる?始め方や基本文法、練習サイト5つを紹介
3.Javaのコンストラクタで引数を渡す方法
Javaでは、引数を付けてコンストラクタを定義することもできます。コンストラクタでは、引数を付ける場合に「クラス名(引数型 引数名)」と記述します。
以下の「ConstructorNumExample」の例では、引数ありのソースコードとして、コンストラクタ本体が受け取る引数に「(int num)」と入れています。
class ConstructorNumExample { ConstructorNumExample(int num) { System.out.println(num + "度目の実行です"); } }
public static void main(String[] args) { ConstructorNumExample example = new ConstructorNumExample(1); } } |
コンストラクタに渡す引数は、「new ConstructorNumExample()」で()内の引数に記載した「1」です。1が渡されて、コンストラクタが1を引数に実行します。
4.Javaのコンストラクタをオーバーロードする方法
Javaのコンストラクタでは、オーバーロードして使用することができます。
オーバーロードとは
オーバーロードとは、日本語で「多重定義」と訳されるプログラミング用語です。名前の通り、複数の同名メソッドを同じクラス内で使えるという特徴があります。そのため、メソッドの特殊な使い方となるコンストラクタでもオーバーロードして使うことが可能です。
具体的な使い方は、型や引数、その順番を変えます。書き方については次からのソースコード例で示します。
オーバーロードしたコンストラクタ
以下は、コンストラクタの引数ありで実行した先程の例に、オーバーロードの条件を満たした(同名のコンストラクタで引数の型や順番が異なるように配置した)ものです。
class ConstructorNumExample { ConstructorNumExample(int num1) { System.out.println(num1 + "度目の実行です"); } ConstructorNumExample(String st1) { System.out.println(st1 + "度目の実行です"); } ConstructorNumExample(int num2, String st2) { System.out.println(num2 + st2); } }
public static void main(String[] args) { ConstructorNumExample example1 = new ConstructorNumExample(1); ConstructorNumExample example2 = new ConstructorNumExample("3"); ConstructorNumExample example3 = new ConstructorNumExample(3, "度目の実行です");
} |
上記では、同じメソッド名でありながら、3つの出力結果をエラーなくオーバーロードして実行することができます。
オーバーロード時に「this()」を使う
オーバーロードでは、同名メソッドを繰り返し使える性質を利用して複数のコンストラクタを実行できます。このとき、同じコンストラクタ本体を繰り返す場合、「this()」でコード文を部分的に省略することができます。具体的には、「this()」は同じクラス内の別のコンストラクタを呼び出して実行可能です。
例えば、以下のソースコード例では、「ConstructorNumExample」のコンストラクタ名で最初に定義されている「System.out.println()」(=コンストラクタ本体)をthisで呼び出し、引数を変えて繰り返し使っています。
class ConstructorNumExample { ConstructorNumExample(int num1, String st1) { System.out.println(num1 + st1); }
this(num2, "度目の実行です"); }
this(3, st2); } }
public static void main(String[] args) { ConstructorNumExample example1 = new ConstructorNumExample(1, "度目の実行です"); ConstructorNumExample example2 = new ConstructorNumExample(2); ConstructorNumExample example3 = new ConstructorNumExample("度目の実行です"); } } |
ただし、使用には制約もあって、「同じクラス内」で同名コンストラクタがオーバーロードされていることです。また、Javaの仕様としてコンストラクタの先頭(最初の行)に「this()」を記述することもルールとして守る必要があります。
関連記事
Javaのオーバーライド攻略|オーバーロードとの違いや使い方・条件・戻り値などわかりやすく解説
5.スーパークラスを継承してコンストラクタを使用する
コンストラクタは、スーパークラスを継承して使うこともできます。
スーパークラスとは
スーパークラスは、親クラスを子クラスに継承して使えるクラスです。この親子関係をスーパークラス・サブクラスと言い換えられます。
新たなクラスに、再度、同じフィールドやメソッドの記述が不要となるため、作業負担を減らす目的でJavaプログラムで使われます。そのため、スーパークラスは、オブジェクト指向プログラミング言語のJavaが持つ大きな特徴の1つです。
コンストラクタは継承されない
コンストラクタの場合、親のクラスを継承する際に、子クラス(サブクラス)はコンストラクタを継承しません。継承を前提にソースコードを組むとエラーが出ます。
例えば、引数のないコンストラクタを子クラスに入れた場合、親クラスに引数があるとエラーが出ます。原因は、親クラスの初期化をしていない状態で、サブクラスに親のコンストラクタを呼び出し実行しようとすることにあります。
【エラーが出るコード例】
class ConstructorNumExample { ConstructorNumExample(int num) { } } class SubClassExample extends ConstructorNumExample { SubClassExample() { } } public class Main { public static void main(String[] args) { SubClassExample example = new SubClassExample(1); } } |
そこで、引数ありのコンストラクタを「SubClassExample(int num)」にして、その本体内に「super(num)」で明示的に親クラスのコンストラクタを呼び出します。
ただし、親クラスが引数なしで、子クラスが引数ありの場合、暗黙的に呼び出されるため、エラーが出ずに子は親のコンストラクタを実行することが可能です。これは、親クラスのコンストラクタを継承しているのではなく、子クラスに呼び出されても問題なくコンストラクタが使用できているためです。その場合、「super()」で明示的に記述する必要はありません。
「super()」で親クラスのコンストラクタを呼び出す
「super()」は親クラスのコンストラクタを継承しないことで起こるエラーを回避する方法です。それを踏まえて、ソースコード例を以下に示します。
class ConstructorNumExample { ConstructorNumExample(int num, String st) { System.out.println(num + st); } } class SubClassExample extends ConstructorNumExample { SubClassExample(int num, String st) { super(num, st); } } public class Main { public static void main(String[] args) { SubClassExample example = new SubClassExample(1 ,"度目の実行です");
} |
上記の例では、親クラスの「ConstructorNumExample」と子クラス「SubClassExample」を用意し、「super()」で親のコンストラクタを呼び出しています。そして、インスタンスは、サブクラスを指定しています。
この例では、子クラスのインスタンスを生成しています。子クラスのコンストラクタで super() を使用するのは、継承関係において子クラスのオブジェクトを生成する際に、親クラスの部分も適切に初期化するためです。
なお、親クラスのインスタンスも通常は直接生成可能です。
関連記事
Java superとは?メソッド呼び出しなど基本的な使い方や2つ上の親クラスの参照方法を解説
6.Javaでコンストラクタを利用するときの注意点
Javaのコンストラクタには、利用時に注意すべき事柄があります。以下に、特に押さえたい注意事項を取り上げます。
使用できる修飾子に制限がある
コンストラクタでは、使える修飾子に制限があります。修飾子とは、Javaで「アクセス修飾子」(public、privateなど)や「final修飾子」(final)などのキーワードを指します。
コンストラクタで使える修飾子は、アクセス修飾子が基本となり、他の修飾子は使えません。例えば、「final」や「static(静的)」「void」などです。
また、修飾子が不要になる場合と必要な場合があり、それを使い分けることが必要となります。例えば、オブジェクトの使用範囲を広げて別のクラスで作成したいときには「public」を付けるなどです。そのため、コンストラクタでは修飾子が基本不要で、必要な場合だけ付けるのがスタンダードです。
Javaのコンストラクタは戻り値を設定できない
コンストラクタは特別なメソッドとして一度だけ実行されるため、戻り値を設定できない決まりです。戻り値が設定できないということは、基本「void」も入れることはありませんし、ただし、処理を途中で終了するための値を返さない return; 文は使用可能です。値を返そうとする return 値; はコンパイルエラーになるので気をつけましょう。
使用をおすすめできないケースがある
Javaのコンストラクタ実行は、オブジェクトを扱う上で必要な処理です。しかし、使いすぎたり、複雑な引数を扱いすぎると、処理が重くなり使い勝手も悪くなります。
また、インスタンスの生成時は、値の格納や実行タイミングがシビアになり、システム上のエラーが起こりやすいことです。無理にインスタンスからメソッドを使用する場合、複雑になりすぎて参照のタイミングや記述ルールを守ることが難しくなります。
7.Javaのコンストラクタでよくある質問
ここでは、コンストラクタに関してよくある質問に回答します。
1文字目がなぜ小文字ではなく大文字?
コンストラクタ名の1文字目が大文字な理由は、クラス名と同じ必要があるためです。通例のメソッド名の規則(小文字)を無視して書くことから、すでに慣れている方にとっては違和感がありますが、コンストラクタを書く場合はこちらが正しい記述の仕方です。
コンストラクタはなぜ他のメソッドと同じように扱われない?
Javaのコンストラクタが通常のメソッドと比べて、扱いが異なります。その理由は、システム内では無名のメソッドとして実行されることが関係しています。名前のあるメソッドと扱いが違うのは仕方ありません。
引数のエラーが発生したときはどうする?
エラーに対しては、インスタンスの新たな定義とコンストラクタの引数をチェックすることです。引数の不一致はエラーとして起こりやすく、インスタンスの引数が正しく設定されているか確認しましょう。
関連記事
Java初心者ガイド|Java学習のロードマップと効率良い勉強方法を解説
8.まとめ
今回は、Javaのコンストラクタを定義する方法や使用の手順・使い方、注意点などを解説しました。コンストラクタは、Javaのメソッドで特殊な扱いとして、インスタンスの作成時に1度だけ実行されます。
戻り値などもなく、制約も多いため、複雑な引数を渡したり、コンストラクタ内部で別のメソッドを異なるタイミングで使うなどには向いていません。注意点を踏まえて、ソースコード例を参考に実践的なコンストラクタの使い方に挑戦しましょう。
本記事が皆様にとって少しでもお役に立てますと幸いです。
「フリーランスボード」は、数多くのフリーランスエージェントが掲載するITフリーランスエンジニア・ITフリーランス向けの案件・求人を一括検索できるサイトです。
開発環境、職種、単価、稼働形態、稼働日数など様々な条件から、あなたに最適なフリーランス案件・求人を簡単に見つけることができます。
単価アップを目指す方や、自分の得意なスキルを活かせる案件に参画したい方は、ぜひ「フリーランスボード」をご利用ください。