【はじめてのJava】コンストラクタの注意点(継承時)【クラスの継承編】
はじめてのJava
このシリーズでは、初めてJavaやプログラミングを勉強する方向けに、Javaによるプログラミングの基礎を説明していきます。
目標レベルは、Javaの資格試験の一つである「Oracle Certified Java Programmer, Silver」(通称Java Silver)に合格できる程度の知識の習得です。
はじめてJavaやプログラムに触れる方にもできるだけわかりやすい解説を心がけていきます。
クラスの継承編
クラスの継承編では、Javaを扱う上で重要な「クラスの継承」について扱っていきます。
前回はコンストラクタ呼びなおしの注意点を扱いました。
今回は継承時のコンストラクタの呼びなおしの注意点を扱います。
目次
コンストラクタ呼びなおし時の注意点
コンストラクタを呼びなおす際には コンストラクタ内の最初の処理でコンストラクタの呼びなおしを行う必要があります 。
実は、クラスを継承している場合には、もう一つ、コンストラクタに関する注意点があります。
コンストラクタ呼びなおし時の注意点(継承時)
実はクラスを継承する場合、親クラスとなる側のクラスに注意点があります。
どういうことでしょうか。
デフォルトコンストラクタの自動生成の条件
以前の記事で紹介した通り、クラスの作成時にコンストラクタを定義しなかった場合はコンパイラによって自動的にコンストラクタが定義されます。
この時 コンストラクタが定義されていないときは自動的にデフォルトコンストラクタが生成される と記載しました。
これ自体は書いてある通りです。
これは言い方を変えると コンストラクタが定義されている場合はデフォルトコンストラクタの自動生成は起こらない ということを示しています。
これにあることが組み合わさると、途端によくあるエラーの原因と化します。
そのあることとは何でしょうか。
子クラスをインスタンス化するときの動き
実はそのあることとは、子クラスをインスタンス化するときの動きです。
こちらについては以前別の記事にて特に指定していないと親クラスのインスタンスは引数が空のコンストラクタによって初期化されると紹介しました。
この2つが組み合わさるとコンパイルエラーの要因になりえます。
例
では実際に例を見ながら考えてみましょう。
以下のようなクラスがあったとします。
class ParentClass{ int age; ParentClass(int age){ this.age = age; } }
class ChildClass extends ParentClass{ ChildClass(){ //☆ //何か処理 } }
上記のサンプルは一見するとエラーになる要素が無いように見えるかもしれません。しかし、実は☆の部分でコンパイルエラーを起こします。
なぜでしょうか。
コンパイルエラーの原因
コンパイルエラーの原因を追うために、ChildClassがインスタンス化される際の流れを追ってみましょう。
まず、ChildClassをインスタンス化するためには親クラスであるParentClassのインスタンス化が必要になります。
このとき、ChildClass側ではsuper()を使っていないため、ParentClassの引数がないコンストラクタを呼び出そうとします。
次に、ParentClassを見てみると、「引数ageを取るコンストラクタ」が定義されています。そのため、デフォルトコンストラクタの自動生成が起こりません。その結果、ParentClass側には「引数ageを取るコンストラクタのみ」が存在することになります。
ChildClass側では「ParentClassの引数が空のコンストラクタ」を呼び出そうとするものの、ParentClass側には「引数が空のコンストラクタがない」ためコンパイルエラーとなってしまうのです。
回避策
このエラーを回避する方法はいくつかありますが、一般的には「引数が空のコンストラクタを自力で定義すること」が推奨されています。
また、引数が空のコンストラクタが定義されている場合、一部のフレームワークでの開発に都合が良いです。
そのため、特に「書かない理由」がない場合は引数が空のコンストラクタを必ず書く癖をつけると良いでしょう。
まとめ
・親クラス側に引数が空のコンストラクタが定義されていない場合、コンパイルエラーの要因になることがよくある
・引数が空のコンストラクタを定義しておくと良い
はじめてのJavaシリーズの目次はこちら
クラスの継承編はこちら