2012年2月25日土曜日

java : ジェネリクス型の引数を持つメソッドをinvoke

例えば、javaで「public void testMethod(List arg)」をリフレクションで呼ぶときどうすればいいのでしょう? それなりに検索したけど出てきませんでした。 C#のリフレクションならすぐに見つかるんですけどねぇ。 で、適当にやったら「定義したクラス.getMethod("testMethod", List.class)」で呼べることが判明。 ジェネリクスの部分を省略すればいいようです。

試したコードはこちら。

package reflectgenericslisttest;

import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

public class ReflectGenericsListTest
{
    public static void main(String[] args)
    {
        ReflectGenericsListTest thisApp = new ReflectGenericsListTest();
        thisApp.execute();
    }

    public void execute()
    {
        LinkedList<String> list = new LinkedList<String>();
        list.add("おはよう");
        list.add("いただきます");
        list.add("こんにちは");
        list.add("いただきます");
        list.add("こんばんは");
        list.add("いただきます");
        list.add("さようなら");

        try
        {
            Method method = this.getClass().getMethod("testMethod", List.class);
            method.invoke(this, list);
        }
        catch(Exception exc)
        {
            exc.printStackTrace();
        }
    }

    public void testMethod(List<String> arg)
    {
        System.out.println("testMethod");
        for(String str : arg)
            System.out.println("\t" + str);
    }

    /*
    public void testMethod(List<Integer> arg)
    {
        System.out.println("testMethod");
        for(Integer i : arg)
            System.out.println("\t" + i);
    }
    */
}

あれ? これってオーバーロードどうなるんでしょう?

と思ったらジェネリクスのオーバーロードはできないようです。 オーバーロードしてみたらエラーでname clashとかって言われました。 ↑のコードのコメントを外したらエラーメッセージの確認ができます。

name clash: testMethod(java.util.List) and testMethod(java.util.List) have the same erasure

どうやらjdk6なら戻り値の型を変えればオーバーロードできるようですね。 でもそれはjdkのバグなので使ってはならないそうです。 エラーメッセージで検索したらそれっぽいのが見つかりました。

なんか、togetterの方の人たちは1時間でバグの情報仕入れてますね。 この人たちはどういう検索の仕方をしているんでしょうかね? アンテナ性能の差を痛感します。