Gobble up pudding

プログラミングの記事がメインのブログです。

MENU

スーパークラスで呼び出されているメソッドのサブクラスでのオーバーライドについて

スポンサードリンク

f:id:fa11enprince:20180929032631j:plain

TL;DR

スーパークラスのメソッドはサブクラスでオーバーライドすれば
サブクラスのインスタンス経由で呼び出すと、
たとえスーパークラスでそのメソッドが呼び出されていても当然上書きされる。

経緯

とあるライブラリをカスタマイズしたくて、
そういや、スーパークラスのメソッドってオーバーライドすれば
たとえ、スーパークラス内で呼び出されていたものだったとしても、
サブクラスでオーバーライドしていればオーバーライドしているほうで呼び出されるよね…
って、日本語でうまく説明できているかどうか怪しいですが、
しばらく継承なんか使ってないこともあり、不安になりました。 自分で書くアプリだとよほどフレームワークよりとか、凝ったゲームとか使わない限り
継承はアンチパターンなので使わないですよね。 というわけで検証しました。

クラス図

f:id:fa11enprince:20181124051349p:plain

クラス図は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();   // =>  「ふひひ、こんにちわ」 当然、参照によって決まるのでこうなる
    }
}

うーん相変わらず低レベルな記事だ。まあいいか。