下の例のように super.メソッド名(...)
とすると親クラスのメソッドが呼べますが、リフレクション経由では同じようにできないことが分かりました。
class Parent { public void bang() { System.out.println("Parent.bang!"); } } class Child extends Parent { @Override public void bang() { System.out.println("Child.bang!"); } public void parentBang() { super.bang(); } } public class Main { public static void main(String[] args) throws Exception { new Child().bang(); // => Child.bang! new Child().parentBang(); // => Parent.bang! Parent.class.getMethod("bang").invoke(new Child()); // => Child.bang! // ※ Parent.bang! であって欲しかったけどうまく行かなかった } }
実際 Method#invoke の項には「Java 言語仕様にある通りに動的ルックアップするよ」 (invokevirtual / invokeinterface 相当) とあります。 super 呼び出しは invokespecial なので駄目です。
やりたかったことは次の通りです。 Kink というオレオレ言語を作っていて、 Java のクラスを動的プロキシっぽく拡張したクラスのインスタンスが作れます。で、今度 super 呼び出しができるようにしたのですが、 Java のリフレクションそのままではうまく行きませんでした。
結局どうしたかと言うと、実行時に生成する動的プロキシのクラスに、上例の Child#parentBang と同じように super 呼び出しするだけのブリッジメソッドを追加して、こいつを呼び出すようにしました。
useclass('java.util.ArrayList') &LIST = ArrayList.newwith( 'add' { > &L (&E) stderr.printline(E + ' is added!') L.super('add' E) } ) LIST.add('voxxx') # => 'voxxx' is added! LIST.add('twift') # => 'twift' is added! printline(LIST) # => [voxxx, twift]
Java 7 で導入された MethodHandles.Lookup#findSpecial を使うことでも、 super 呼び出し相当のことができそうですが、 Kink 内部の仕組みと相性が悪いので、今回は使っていません。