TL;DR
スーパークラスのメソッドはサブクラスでオーバーライドすれば
サブクラスのインスタンス経由で呼び出すと、
たとえスーパークラスでそのメソッドが呼び出されていても当然上書きされる。
経緯
とあるライブラリをカスタマイズしたくて、
そういや、スーパークラスのメソッドってオーバーライドすれば
たとえ、スーパークラス内で呼び出されていたものだったとしても、
サブクラスでオーバーライドしていればオーバーライドしているほうで呼び出されるよね…
って、日本語でうまく説明できているかどうか怪しいですが、
しばらく継承なんか使ってないこともあり、不安になりました。
自分で書くアプリだとよほどフレームワークよりとか、凝ったゲームとか使わない限り
継承はアンチパターンなので使わないですよね。
というわけで検証しました。
クラス図
クラス図はObject Aid UMLというecliseのプラグインで書きました http://www.objectaid.com/home
検証コード
検証コードはJavaです
Javaに慣れているせいかvirtual
と書いてOverridableにするよりもfinal
で封じるほうが好きになってきた。
まぁでもC++の場合は思想が違うからな…でもC#はvirtual
なんだよな…。
そのモデリングおかしいだろというのは重々承知ですが、サンプルということなので。
// ここのメソッドいろいろおかしいですが気にせず abstract class Animal { abstract public void greet(); protected void say() { // 継承可能 System.out.println(""); } } class Human extends Animal { public Human() { } @Override public final void greet() { // 挨拶 継承不可 //super.say(); // これだと当然いろいろ破綻する say(); // ライブラリとかでこうなってる場合、こいつを書き換えたいなーと思うことがあるわけ } @Override protected void say() { // 継承可能 System.out.println("\"Hello.\""); // 英語なのはなんか変だが… } } class Japanese extends Human { public Japanese() { } @Override protected void say() { System.out.println("「こんにちは」"); } } class Otaku extends Japanese { public Otaku() { } @Override protected void say() { System.out.println("「ふひひ、こんにちわ」"); } public void majimeNiAisatsu() { super.say(); } } public class Sample { public static void main(String[] args) { Human human = new Human(); human.greet(); // => "hello." Japanese japanese = new Japanese(); japanese.greet(); // => 「こんにちは」 Otaku otaku = new Otaku(); otaku.greet(); // => 「ふひひ、こんにちわ」 otaku.majimeNiAisatsu(); // => 「こんにちは」 // おまけ Human otaku2 = new Otaku(); otaku2.greet(); // => 「ふひひ、こんにちわ」 当然、参照によって決まるのでこうなる } }
うーん相変わらず低レベルな記事だ。まあいいか。