コンストラクタ
このページではコンストラクタの概要、宣言方法、コンストラクタを複数宣言する方法などについて説明します。
概要
インスタンスを生成する際、何らかの初期化処理を行いたい場合があります。その場合、コンストラクタを定義します。コンストラクタは、クラス名と同一のメソッド名である特別なメソッドです。
下の例は、Calculateクラスのコンストラクタを定義した例です。
【例1】コンストラクタの例
class Calculate {
private double syohizei;
//クラス名と同一のメソッド名であるコンストラクタを定義
//コンストラクタの中では、メンバ変数syohizeiの初期値を指定
Calculate (double x) {
this.syohizei = x;
}
----- その他の処理 -----
}
Javaでは、インスタンスを生成する際、必ず何らかのコンストラクタを実行するようになっています。もし、明示的にコンストラクタが定義されていない場合は、引数無し、処理なしのコンストラクタ(デフォルトコンストラクタ)がコンパイル時に自動的に追加されます。そのため、初期化処理を行わない場合は、明示的にコンストラクタを定義する必要はありません。
コンストラクタの宣言方法
コンストラクタの宣言は以下の枠内のフォーマットになります。アクセスレベルはコンストラクタが同一クラス内からしか実行できない、どのクラスからでも実行できるなどを指定するために使用します。コンストラクタ名は属するクラスと同じ名前になります。(引数型 引数名)は初期化処理を実行する際に呼び出し元から渡される値の型とコンストラクタ内で使用される変数名を表します。
コンストラクタ宣言における必須項目はコンストラクタ名 (引数型 引数名)です。コンストラクタ宣言時に付与できる修飾子はアクセスレベルのみです。
アクセスレベル コンストラクタ名 (引数型 引数名)
コンストラクタ宣言時に指定できるアクセスレベルは以下になります。
アクセスレベル | 説明 |
---|---|
public | すべてのクラスでコンストラクタを使用することができます。 |
protected | コンストラクタを宣言したクラスのサブクラスと、同じパッケージ内のクラスでのみコンストラクタを使用することができます。 |
指定なし | コンストラクタを宣言したクラスと同じパッケージ内のクラスでのみコンストラクタを使用することができます。 |
private | コンストラクタを宣言したクラス内でのみ、そのコンストラクタを使用することができます。 |
複数のコンストラクタ
コンストラクタは引数の型や引数の数を変更することで1クラス内に複数宣言することができます。例えば、コンストラクタ内でいくつかのメンバ変数を初期化する場合、指定する初期値があるときは指定し、ない時はデフォルト値を指定するというように、初期化処理を使い分けたいケースがあります。このような時にコンストラクタを複数宣言します。例2では、指定したい初期値がある時、ない時で初期化処理を使い分けるため、コンストラクタを2つ宣言しています。
どのコンストラクタが呼び出されるかは呼び出し元の引数の型、引数の数により決定されます。例2ではインスタンスを生成する際、引数にint型の値を指定しているため、int型の引数を持つSetNumber(int spn)コンストラクタが呼び出されます。
例2
public class SetNumber {
private int basicNum;
private int specialNum;
//int型の引数を持つコンストラクタ
SetNumber (int spn) {
this.basicNum = 100;
this.specialNum = spn;
}
//引数を持たないコンストラクタ
SetNumber () {
this.basicNum = 100;
this.specialNum = 500;
}
public static void main(String[] args) {
//コンストラクタの呼び出しにint型の引数1つを指定
SetNumber insA = new SetNumber(1000);
------その他の処理------
}
}
thisによる他のコンストラクタの呼び出し
コンストラクタを複数宣言する際、同一の処理を複数のコンストラクタで繰り返し記載する場合があります。例2で言うと「this.baiscNum = 100;」の部分になります。仮にこの処理を「this.baiscNum = 200;」としたい場合、両方のコンストラクタの「this.baiscNum = 100;」を修正する必要があります。例2くらいの処理であれば、簡単にコードを修正できますが、複雑な処理になると修正箇所も複雑になり、ミスの要因となります。
このような場合、共通の処理を一方のコンストラクタのみに記載し、別のコンストラクタからはその処理を呼び出すという方法で、コードを簡潔に記載することができます。コンストラクタから別のコンストラクタを呼び出すためには、「this();」を使用します。
例3では共通の処理である「this.basicNum = 100;」をint型の引数を持つコンストラクタ「SetNumber (int spn)」のみに記載します。引数を持たないコンストラクタ「SetNumber ()」には、int型の引数を持つコンストラクタを呼び出すよう「this(500);」を記載します。
これにより「SetNumber ()」のコンストラクタが実行された場合は、「this(500);」により、「SetNumber (int spn)」のコンストラクタが呼び出され、共通の処理である「this.basicNum = 100;」と「this.specialNum = spn;」が実行されます。
コンストラクタ内でthisを使用する場合は文の一番初めに記載する必要があります。それ以外の場所に記載した場合はコンパイルエラーとなります。
例3
public class SetNumber {
private int basicNum;
private int specialNum;
//int型の引数を持つコンストラクタ
SetNumber (int spn) {
//共通の処理をこのコンストラクタのみに記載
this.basicNum = 100;
this.specialNum = spn;
}
//引数を持たないコンストラクタ
SetNumber () {
//int型の引数を持つコンストラクタの呼び出し
this(500);
}
public static void main(String[] args) {
//引数を持たないコンストラクタの呼び出し
SetNumber insA = new SetNumber();
------その他の処理------
}
}
スーパークラスのコンストラクタの呼び出し
クラスの継承のページでクラスの継承を行う際、コンストラクタはサブクラスに継承されないと説明しました。サブクラスでスーパークラスのコンストラクタを使用したい場合はsuperを使用します。superはサブクラスのコンストラクタの一番初めに記載します。それ以外の場所に記載した場合はコンパイルエラーとなります。
【例4】コンストラクタ内でsuperを使用した例。 スーパークラス(ExClass6クラス)
class ExClass6 {
private int memberA;
//スーパークラスのコンストラクタ
ExClass6(int a) {
memberA = a;
}
void showMember(){
System.out.println(memberA);
}
}
サブクラス(SubExClass6クラス)
class SubExClass6 extends ExClass6 {
//サブクラスのコンストラクタ
SubExClass6(){
//superでスーパークラスのコンストラクタを呼び出し
super(10);
}
}
Mainクラス
class Main {
public static void main(String[] args) { SubExClass6 insA = new SubExClass6(); insA.showMember(); }
}
コンストラクタ内で使用するthisとsuperに関して以下の3つの規定があります。
- 1つのコンストラクタ内でthisとsuperの両方を記載することはできない。
- thisとsuperの両方とも記載されていないコンストラクタではスーパ-クラスの引数無しのコンストラクタが呼び出される。
- thisが記載されている時は、thisによって呼び出される先のコンストラクタでスーパークラスの引数無しのコンストラクタが呼び出される。
2、3のスーパークラスの引数無しのコンストラクタの呼び出しに関して注意点があります。継承を行った際、継承されたスーパークラスにおいて引数無しのコンストラクタが宣言されていない場合、サブクラスのコンストラクタ内でスーパークラスの引数無しのコンストラクタが呼び出された時にコンパイルエラーとなります。このエラーの対処策としてはスーパークラスに引数無しのコンストラクタを宣言します。
7コンストラクタ