コンストラクタが存在する理由
前のページでは、クラスを作り、new でオブジェクトを生成しました。コンストラクタは、その new 呼び出しの最中に実際に実行されるコードです。その唯一の目的は、すぐに使える状態のオブジェクトを返すこと、つまり必須フィールドがすべて設定され、中途半端に初期化された状態が残っていないオブジェクトを返すことです。
コンストラクタはメソッドに似ていますが、2つの違いがあります。クラスと同じ名前を持ち、戻り値の型がないこと、void すらないことです。
new Point(3, 4) はオブジェクトを確保し、その後 x = 3、y = 4 でコンストラクタの本体を実行します。new が戻ってくる頃には、p は完全に初期化されています。
this キーワード
上のコンストラクタでは、パラメータは x と y という名前で、フィールドと同じです。this.x は「このオブジェクトに属するフィールド x」を意味し、単なる x はパラメータを指します。this がなければ、x = x は単にパラメータを自分自身に代入するだけで、フィールドは手つかずのまま残ります。
this が必要なのは、パラメータがフィールドを隠してしまうときだけですが、多くの人は明確さのためにどこでも使います。よくある間違いは、名前が衝突するときに this を忘れることです。コードはコンパイルされ、実行されますが、フィールドを既定値(null、0、false)のまま黙って放置してしまいます。
デフォルトコンストラクタ
コンストラクタをまったく書かなければ、Javaはひそかにデフォルトコンストラクタを用意します。これは public で引数なし、追加で何もしないコンストラクタです。だからこそ、コンストラクタを持たないクラスでも new が動いていたのです。
落とし穴:何らかのコンストラクタを書いた瞬間に、無料のものは消えます。
class Box {
int size;
Box(int size) { // これで引数なしコンストラクタはなくなる
this.size = size;
}
}
new Box(); // コンパイルエラー:コンストラクタ Box() は存在しない
それでも new Box() を動作させたい場合は、引数なしコンストラクタを自分で宣言します。
コンストラクタのオーバーロード
クラスは、パラメータリストが異なってさえいれば複数のコンストラクタを持てます。これはメソッドのオーバーロードをコンストラクタに適用しただけのものです。それぞれがオブジェクトを構築する別々の方法を提供します。
Javaは、new に渡す引数の数と型に応じて、一致するコンストラクタを選びます。
this() による連鎖
上の重複に注目してください。各コンストラクタが自分でフィールドを代入しています。これは、あるコンストラクタが this(...) で別のコンストラクタを呼び出すことで避けられます。この呼び出しは、コンストラクタ内の最初の文でなければなりません。
これで、実際の初期化は1か所にまとまりました。小さいコンストラクタは既定値を埋めて作業を転送するだけです。もし this(...) の前に文を置こうとすると、コンパイラはそれを拒否します。
コンストラクタと super()
すべてのコンストラクタは、まず暗黙のうちにスーパークラスのコンストラクタを呼び出します。何も書かなければ、Javaは本体の先頭に隠れた super()(スーパークラスの引数なしコンストラクタ)を挿入します。これに直接向き合うのは、サブクラスを作り始めたときで、それが次のトピックです。
class Animal {
String name;
Animal(String name) { this.name = name; }
}
class Dog extends Animal {
Dog(String name) {
super(name); // ここでは親のコンストラクタを明示的に呼び出さなければならない
}
}
Animal には引数なしコンストラクタがないため、Dog は super(name) を明示的に呼び出さなければなりません。頼れる無料の super() は存在しないのです。this() と同様に、super(...) の呼び出しもコンストラクタ内の最初の文でなければなりません。
次へ:継承
コンストラクタは単一のオブジェクトを初期化しますが、super() はすでにもっと大きなものを暗示していました。クラスは他のクラスの上に構築でき、そのフィールド、メソッド、コンストラクタを再利用できます。その関係、つまりあるクラスが別のクラスを拡張することが継承であり、それが次のページです。
よくある質問
Javaのコンストラクタとは何ですか?
コンストラクタは、new でオブジェクトを生成するときに実行される特別なメソッドです。クラスと同じ名前を持ち、戻り値の型がありません(void すらありません)。その役割は、新しいオブジェクトを有効な初期状態にすることで、通常はコンストラクタの引数をオブジェクトのフィールドに代入して行います。
Javaにおけるコンストラクタとメソッドの違いは何ですか?
コンストラクタはクラスとまったく同じ名前を持ち、戻り値の型を宣言せず、オブジェクトが生成されるときに new でのみ呼び出せます。通常のメソッドは独自の名前を持ち、戻り値の型(または void)を宣言し、既存のオブジェクトに対して呼び出されます。コンストラクタは初期化を行い、メソッドはその後の処理を行います。
Javaでコンストラクタを書かないとどうなりますか?
コンパイラは無料で引数なしのデフォルトコンストラクタを用意します。これはパラメータを取らず、暗黙の super() 呼び出し以外は何もしません。しかし、自分で何らかのコンストラクタを書いた瞬間に、この無料のものは消えてしまいます。そのため、引数付きコンストラクタを追加してもなお new Thing() を動作させたい場合は、引数なしコンストラクタを明示的に宣言する必要があります。