2012-08-28 22 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