super()の連鎖
super()の連鎖
このレッスンでできるようになること。コンストラクタが実際にどの順番で走るのかを追えるようになり、暗黙の super() が原因のコンパイルエラーを見抜けるようになります。
コンストラクタの1行目に何も書かないと、コンパイラが引数なしの super() を勝手に挿し込みます。この見えない1行が試験のほぼすべての仕掛けの正体です。
class A {
A() { System.out.print("A"); }
}
class B extends A {
B() { System.out.print("B"); }
}
class C extends B {
C() { System.out.print("C"); }
}
new C();出るのは ABC です。C の中で super() が呼ばれ、その B の中でまた super() が呼ばれ、A まで登り切ってから戻りながら実行されるので、親から先に終わります。
引数なしのコンストラクタが無いとき
ここが最大の罠です。親が引数ありのコンストラクタだけを持つと、コンパイラは引数なしの既定コンストラクタを作りません。すると子の暗黙の super() が呼ぶ相手を失い、子の側がコンパイルエラーになります。子が書かれていないのにエラーが子に出るので、原因を親だと気づけるかが分かれ目です。直し方は、子で明示的に super(値) を書くことです。
1行目にしか書けない
super(...) と this(...) はどちらもコンストラクタの最初の文でなければならず、1つのコンストラクタで両方は書けません。this(...) を書いた場合は同じクラスの別のコンストラクタへ渡り、その先で親が呼ばれます。
なお初期化の順番は、親のコンストラクタが終わってからフィールド初期化子と初期化ブロック、そのあと自分のコンストラクタ本体です。親のコンストラクタから子のオーバーライドされたメソッドを呼ぶと、子のフィールドがまだ初期値のままで見える、という有名な事故もここから来ています。
演習では、呼び出しの順番をログとして組み立てて確かめます。
要件
kindが1のときだけBを、それ以外はCを生成する- 生成の前に
logを空にする - クラス
A、B、Cは変更しない
入出力例
trace(1) → "A5B"
trace(2) → "A5BC"ヒント
編集 LuaGate編集部