2012-08-28 54 views
3

今天我想出了一个解决方案,涉及在运行时创建类,解析文件,使用Java中的Reflection API之后。在运行时绑定到正确的构造 - Java的

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 

然后我要创建类型org.powertac.common.Tariffclassnew告诉我需要创建一个新的对象,它需要一个double rate作为参数,在这种情况下6。不过,我不知道这需要一个double,仅有参数是String6)。我怎么能创建/转换/转换为正确的类型,然后将其分配给构造?我首先想到的是创建一个符号表,但我想知道更简单的解决方案...

+0

只是为了我的好奇心通过反射构造的构造函数的参数数组的参数,一般要解决什么问题?为什么不使用标准的Java序列化机制(序列化API,坚持XML/JSON等) – udalmik

+0

@mudalov你能给我更多的细节吗? – cybertextron

回答

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); 

如果你不知道类型的你的论点,你将不得不测试集对抗返回的类数组参数对于每个由Class.getConstructors()返回的构造函数,都会返回210,直到找到与您的参数数组相匹配的构造函数。更具体地说,参数数组和类数组的长度相同,并且类数组中的每个类传递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序列化是如何工作的),这样就可以用自己的类型构造

+0

你能给我更多的细节吗? – cybertextron

+0

@philippe我给答案增加了一些细节。 – Dev

+0

如果传递给'Constructor.newInstance(Object ...)'的值不能分配给由'Constructor返回的Class数组表示的类。getParameterTypes()'以正确的顺序输入正确数量的参数,那么你会在你的问题中看到参数类型不匹配异常。 – Dev