こんなことがしたい
例えば以下のようなクラスがあった場合。
public interface Base { } public class Sub1 implements Base { } public class Sub2 implements Base { }
以下のようにすると test(new Sub1()) のような呼び出しで method(Sub1 sub1) のメソッドが呼ばれるのではなかろうか?
private test(Base b) { Class type = Class.forName(b.getClass().getCanonicalName()); method(type.cast(b)); } private void method(Base base) { System.out.println("base"); } private void method(Sub1 sub1) { System.out.println("sub1"); } private void method(Sub2 sub2) { System.out.println("sub2"); }
と思っていましたが、メソッドのオーバーロードは、オーバーライドと異なり、コンパイル時に呼び出し対象のメソッドを静的に決定するため、上記コードは無効です。
普通はポリモーフィズムで必要なメソッドを該当のクラス内で定義しますが、対象のクラスがいじれない場合は instanceof にてしこしこと条件分岐する必要があります。
リプレクションを使って
無理やり対応しようとすると以下のような感じになります。ちゃんとやろうとすると、もう少し作り込む必要ありますが・・
private void test(Base b) throws Exception { invokeMethod(new Sub1()); invokeMethod(new Sub2()); } private void method(Sub1 sub1) { System.out.println("sub1"); } private void method(Sub2 sub2) { System.out.println("sub2"); } private void invokeMethod(Object obj) { Method targetMethod = null; for (Method method : getClass().getDeclaredMethods()) { if (!method.getName().equals("method")) { continue; } for(Type argType : method.getParameterTypes()) { if (argType == obj.getClass()) { targetMethod = method; } else { targetMethod = null; break; } } if (targetMethod != null) { try { targetMethod.invoke(this, obj); return; } catch (Exception e) { throw new IllegalArgumentException(e); } } } }
実行結果は以下のようになります。
sub1 sub2
でも、ポリモーフィズムで対応するのが正解ですね・