3

私は今日、JavaのReflection APIを使用して、ファイルを解析した後、実行時にクラスを作成することを含むソリューションを思いつきました。

    while ((line = textReader.readLine()) != null)
    {
        Pattern p = Pattern
            .compile("([^:]+):([^:]+)::([\\d]+)::([^:]+)::(.+)");
        Matcher m = p.matcher(line);
        if (m.find())
        {
            String id = m.group(1);
            String className = m.group(2);
            int orderOfExecution = Integer.valueOf(m.group(3));
            String methodNameOrNew = m.group(4);
            Object[] arguments = m.group(5).split("::");
            if (methodNameOrNew.compareTo("new") == 0)
            {
                System.out.println("Loading class: " + className);
                if (className.contains("Competition"))
                {
                    continue;
                }
                else if (className.contains("$"))
                {
                    continue;
                }
                else
                {
                    Class<?> cl = Class.forName(className);
                    printMembers(cl.getConstructors(), "Constructor");
                    Constructor<?>[] cons = cl.getConstructors();
                    Object obj = cons[0].newInstance(arguments);
                    this.map.put(id, obj);
                }
            }
        }
    }

およびprintMembers()

private static void printMembers(Member[] mbrs, String s)
{
    out.format("%s:%n", s);
    for (Member mbr : mbrs)
    {
        if (mbr instanceof Field)
            out.format("  %s%n", ((Field) mbr).toGenericString());
        else if (mbr instanceof Constructor)
            out.format("  %s%n", ((Constructor) mbr).toGenericString());
        else if (mbr instanceof Method)
            out.format("  %s%n", ((Method) mbr).toGenericString());
    }
    if (mbrs.length == 0)
        out.format("  -- No %s --%n", s);
    out.format("%n");
}

ただし、次のエラーが発生します。

Loading class: org.powertac.common.TariffSpecification
Constructor:
  public org.powertac.common.TariffSpecification(org.powertac.common.Broker,org.powertac.common.enumerations.PowerType)

java.lang.IllegalArgumentException: argument type mismatch
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
    at Parser.parse(Parser.java:64)
    at Parser.main(Parser.java:137)

arguments[]は:1 : CONSUMPTION。適切なコンストラクターを作成し、それに適切な引数(型)を与えるにはどうすればよいですか?たとえば、私が使用しているサンプルパーサーには、次のものがあります。

2233:org.powertac.common.Tariff::6::new::6

次にclass、タイプのaを作成する必要がありますorg.powertac.common.Tariffnew新しいオブジェクトを作成する必要があることを通知します。double rateこの場合、引数としてasを取り6ます。ただし、それが取るかどうかはわかりません。double引数はString6)だけです。作成/変換/正しい型にキャストしてからコンストラクターに割り当てることはできますか?最初に考えたのはシンボルテーブルを作成することでしたが、もっと簡単な解決策が必要です...

4

1 に答える 1

3

Class.getConstructor(Class...)渡したい引数に適したコンストラクターを選択するために使用する必要がありますConstructor.newInstance(Object...)

あなたの例で1 : CONSUMPTIONは、配列に相当する手段の配列を想定します

Object[] arguments = new Object[]{Integer.valueOf(1), "CONSUMPTION"};

したがって、次のように呼び出します

Class clazz = ... //Whatever class reference you have
Constructor c = clazz.getConstructor(Integer.class, String.class);
Object obj = c.newInstance(arguments);

引数の型がわからない場合は、引数配列に一致するコンストラクターが見つかるまで、Constructor.getParameterTypes()によって返されるコンストラクターごとに、によって返されるクラス配列に対して引数セットをテストする必要があります。Class.getConstructors()より具体的には、引数の配列とクラスの配列は同じ長さであり、クラス配列の各クラスはClass.isAssignableFrom(Class)、引数配列の同じ位置にある値のクラスを渡します。

上記のコードでの実装

    public boolean canConstruct(Object[] args, Constructor<?> c){
        Class<?>[] paramTypes = c.getParameterTypes(); 
        if(args.length != paramTypes.length){
            return false;
        }

        int i = 0;
        for(Object arg: args){
            if(!paramTypes[i].isAssignableFrom(arg.getClass())){
                return false;
            }
                    i++;
        }

        return true;
    }

これを使用するには、コンストラクターに渡したい引数配列が必要です。型情報が含まれるように入力を編集してみてください (これは、Java シリアル化のしくみに似ています)。これにより、独自の型コンストラクターを使用してリフレクションを介してコンストラクター引数配列の引数を構築できます。

于 2012-08-28T02:31:56.107 に答える