odz buffer

2006-12-08

[]Java でメソッドを静的にディスパッチする

普通にReflectionを使っても無理。

基本となるメソッドがインスタンスメソッドの場合、動的メソッドルックアップを使用して呼び出しが行われ、ターゲットオブジェクトの実行時の型に基づいてオーバーライドが実行されます (『Java 言語仕様第 2 版』のセクション 15.12.4.4 を参照)。

Method (Java 2 Platform SE 5.0)

要するに呼び出したい Class に対して getMethod で Method オブジェクトを取得しようがインスタンスメソッドは invoke を呼び出した時点で動的にディスパッチされてしまう。

が、言語仕様を確認するとこうある。

メソッド検索のための戦略は,呼出しのモードに依存する。

もし呼出しのモードが static であるならば,ターゲットの参照は必要なく,上書きも許されない。 クラス T のメソッド m が呼び出されるメソッドになる。

そうでなければ,インスタンスメソッドが呼び出され,ターゲットの参照が存在する。 もしターゲット参照が null であるならば,この時点で NullPointerException が投げられる。 そうでなければ,そのターゲットの参照は ターゲットオブジェクト (target object) を参照すると言い,及び呼び出されたメソッドで this キーワードの値として使用される。 呼出しのモードのための他の四つの可能性を検討する。

もし呼出しのモードが nonvirtual であるならば, 上書きは許されない。 クラス T のメソッド m が呼び出されるべきとする。

そうでなければ,呼出しのモードは interface,virtual 又は super のいずれかになり,上書きされるかもしれない。 その場合,動的なメソッド検索 (dynamic method lookup) が使用される。 動的な検索の過程はクラス S から開始され,次のように決定される。

Java言語規定 式

つまり nonvirtual なモードであればいい。15.12.3節にあるとおり private なインスタンスメソッドは nonvirtual になる(private メソッドが動的にディスパッチされても困るし)。

ということで、結論としてはこんなの。

import java.lang.reflect.Method;

class B {
    @SuppressWarnings("unused")
    private void method() {
        System.out.println("B#method");
    }
}

class D extends B {
    @SuppressWarnings("unused")
    private void method() {
        System.out.println("D#method");
    }
}

public class MethodTest {
    public static void main(String[] args) throws Exception {
        B a = new D();
        Method method = B.class.getDeclaredMethod("method", new Class[0]);
        method.setAccessible(true);
        System.out.println(method.getDeclaringClass());
        method.invoke(a, new Object[0]);
    }
}

まぁ、もともと静的にディスパッチされているものを Reflection 使って、やっぱり静的にディスパッチしているわけで、あんまり面白くないというか、当初の目的と違う気がする。

ASMJavassist なんかの bytecode manipulation framework を使えば無理矢理できそうな気がしないでもないが、Java の仕様を見る限り、代わりに普通にメソッドコールしても動的ディスパッチできなくなるというオチが待ってそう。

sumimsumim 2006/12/08 18:37 どうもありがとうございます。さすが仕様書、いろいろと(入門書では学べない)重要なことが書いてありますね。

odzodz 2006/12/09 04:59 ですね。仕様書があるなら仕様書にあたるのが確実ですね。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証