3

我今天想出了一个解决方案,涉及在运行时创建类,在解析文件后,使用 Java 中的反射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类型的org.powertac.common.Tariff(new告诉我需要创建一个新对象,并且double rate在这种情况下它需要 a 作为参数6。但是,我不知道它需要 a double,只有参数是String( 6)。如何我可以创建/转换/转换为正确的类型,然后将其分配给构造函数吗?我的第一个想法是创建一个符号表,但我想知道一个更简单的解决方案......

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 数组测试参数集,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 回答