[Java] 静的型言語のスタティックメソッド

2018年11月12日月曜日

Java

[PHP] 遅延静的束縛では、PHPのself呼び出しとstatic呼び出しの違いについて書いた。
結局、static呼び出しではクラスレベルでのオーバーライドを実現しているのだった。
静的型言語ではその辺りはどうなってるんだっけ?例えば、Javaは。

Javaのstaticメソッド

class A {
    public static void main(String ... args) {
        A.method();
        B.method();
        C.method();
    }

    protected static void method() {
        System.out.println("A");
    }
}

class B  extends A {
}

class C  extends B {
    protected static void method() {
        System.out.println("C");
    }
}
実行結果
A
A
C

Javaのstaticメソッドはコンパイル時にクラスと結びつくため、PHPのself呼び出しと同様になる。
クラスと結びつくと言っても、B.methodを呼び出すと、A.methodが実行されるため、staticメソッドでも継承は実現されていると言える。

オーバーライドではなく、隠ぺい

C extends Bでは、クラスC独自のメソッドを実装しているため、C.methodを呼び出すとA.methodではなく、C.methodが実行される。
これはオーバーライドではないのか?
class A {
    public static void main(String ... args) {
        A.publicMethod();
        B.publicMethod();
        C.publicMethod();
    }

    public static void publicMethod() {
        method();
    }

    protected static void method() {
        System.out.println("A");
    }
}

class B  extends A {
}

class C  extends B {
    protected static void method() {
        System.out.println("C");
    }
}
実行結果
A
A
A

C.publicMethodを呼び出しても、C.methodは実行されない。
つまり、実行時のポリモーフィズムは実現されていないことになるため、オーバーライドとは言わないみたい。
この違いがあるため、サブクラスによるstaticメソッドの上書きは隠ぺい(シャドーイング)と呼ぶ。

語の使い方があっているか分からないけど、隠ぺい(シャドーイング)はコンパイル時のポリモーフィズムで、オーバーライドは実行時のポリモーフィズムを実現しているといったところか。

差分プログラミングについて

少し視点を変えて、オーバーライドと差分プログラミングについて考えてみよう。

差分プログラミングというのは大きな動作は全体で同じだけど、部分部分で異なる箇所のみを具象クラスで実装することにより、コードのコピー防止や実装量の軽減を実現して保守性を高めるための取り組みだった。
そう考えると、そもそもオーバーライドは差分プログラミングを実現するための手段と言える。

では、隠ぺい(シャドーイング)は差分プログラミングを実現しているだろうか?

これは先ほどのA.methodとC.methodの例を逆向きの視点から言っているにすぎない。
差分プログラミングを実現していないという観点からも、staticメソッドの上書きはオーバーライドではないということになる。