Javaのクラスを作る上で、継承で出来ることと出来ないことがわかってきたのでまとめ。
今日は継承とコンストラクタ。
(学習中のメモなので随時更新予定。)
子クラスのコンストラクタでエラー
継承で子クラスを作る際、以下のようなコードでなぜかエラーが出ました。
class Cat{
String name;
Cat(String s){
name = s;
}
}
class Lion extends Cat{
}
一見問題無さそう(Lionクラスの存在意味がないことを除けば)に見えますが、これだとエラーが出ます。(error: constructor Cat in class Cat cannot be applied to given types...)
無論、Lionにてコンストラクタを記述していないからではありません。コンストラクタは記述されていなけい場合、暗黙的に「何もしない」コンストラクタを呼び出し、実行してくれることになっています。
原因
では何がいけないかというと、理由は以下の2つです。
-
子クラスのコンストラクタでは、デフォルトでは(やはり暗黙のうちに)親クラスの引数なしコンストラクターをまず実行することになっているから。
-
コンストラクタを明記した場合、もともと用意されている「何もしない」引数なしコンストラクタは、上書きされて無くなってしまうから。
例えば、
class Cat{
String name;
}
class Tiger extends Cat{
Tiger(){
System.out.println("ガルルルルァ!");
}
}
上記のようなコードでも、実はTigerクラスのインスタンスが作られた時には、System.out...の前に、親クラスCatの(何もしない)コンストラクタが実行されています。
しかし、
class Cat{
String name;
Cat(String s){
System.out.println(s);
}
}
class Lion extends Cat{
Lion(){
System.out.println("ガルルルルァ!");
}
}
このように Catに引数有りのコンストラクタを書いてしまうと、元々用意されていた引数"無し"の何もしない暗黙コンストラクタは上書きされて無くなってしまいます。その為 Cat には、引数なしのコンストラクタが存在しない状態となります。
ですが上記のように、子クラスのコンストラクタにおいては、デフォルトでは、親クラスの引数なしコンストラクタが実行されることになっています。よって必要なものが存在しない為、エラーが出ることとなります。
対策
では、冒頭のコードでエラーを出ないようにするには、どのようにしたらいいのでしょうか。それは、子クラスにコンストラクタを記述し、その中で親クラスの(引数なしではなく)引数ありのコンストラクタを実行するよう明記することです。
以下のように書きます。
class Cat{
String name;
Cat(String s){
name = s;
}
}
class Lion extends Cat{
Lion(String s){
super(s);
}
}
これで、意図を変えないままにエラーを回避できます。
まとめ
親クラスが引数有りコンストラクタ(のみ)の場合は、めんどくさがらずに子クラスにもコンストラクタを書こう!(そして親クラスの引数有りコンストラクタを実行)