ソースコードの処理フローを読み違えたため、備忘録として残す。
コード
BACK(spring mvc) ↓
class Parent {
void method1() {
...
method2(); //⭐️
...
}
void method2() {
...
}
}
@Controller
@RequestMapping("a/dd/ress")
class Child extends Parent {
@GetMapping("/method1")
void method1() {
...
super.method1();
...
}
@Override
void method2() {
super.method2();
...
}
}
FRONT(JSP) ↓
...
<script>
...
document.main.action = "a/dd/ress/method1";
document.main.submit();
...
</script>
勘違いしていた点
リクエストが到達するとChildの処理が始まり、super.method1()を経由して親のmethod1()が実行される。
では次の⭐️のところで、処理がどこへ遷移するのか???
Parentのmethod2()が呼ばれると考えたが、実際にはChildのmethod2()が呼ばれていた。
デバッグモードで確認したらParentのmethod2()に遷移したように見えたので、もっと分からなくなったが、
それは子クラスのオーバーライドされたメソッド内にあるsuper.method2();が呼び出されたせいだった。
なぜそうなる?
実際のインスタンス(中身)が何であるかによって、呼ばれるメソッドが決まる。
親クラスのmethod1()内でmethod2()を呼ぶ処理は、暗黙的に this. method2()として実行される。
この時のthisは「コードが書かれている親クラス」ではなく、
「実行時点に実際にメモリ上に生成されたインスタンス(=Child)」を指す。
そのため、子クラスでオーバーライドされたメソッドが優先される。
Springは継承関係にあるBeanをどう生成するのか
Javaの「親クラス a = new 子クラス()」という多態性(ポリモーフィズム)の概念が、Spring内部でもそのまま使われている。
Springは起動時、@Controllerが付与されたChildクラスを見つけ、内部的にnew Child()を実行してBeanとしてコンテナに登録する。
ParentはアノテーションがないのでSpringがBeanとしてコンテナに登録されないが、
ChildはParentを継承しているので、
以下のような見えないコンストラクタによって親オブジェクトが生成される。
class Child extends Parent {
Child() {
super();
}
}