2010-06-21 63 views
8

考慮下面的代碼片段:使用java.lang.reflect.getMethod多態方法

public class ReflectionTest { 

    public static void main(String[] args) { 

     ReflectionTest test = new ReflectionTest(); 
     String object = new String("Hello!"); 

     // 1. String is accepted as an Object 
     test.print(object); 

     // 2. The appropriate method is not found with String.class 
     try { 
      java.lang.reflect.Method print 
       = test.getClass().getMethod("print", object.getClass()); 
      print.invoke(test, object); 
     } catch (Exception ex) { 
      ex.printStackTrace(); // NoSuchMethodException! 
     } 
    } 

    public void print(Object object) { 
     System.out.println(object.toString()); 
    } 

} 

getMethod()顯然是無法察覺到String可以反饋給需要Object(的確是一個方法,它的文檔中說,它會使用指定的名稱和完全相同的形式參數類型)查找方法。

有沒有找到方法反思一個簡單的方法,像getMethod()做,但考慮多態性考慮進去,這樣,當與("print", String.class)參數查詢上述反射的例子可以找到print(Object)方法?

+1

我在http://stackoverflow.com/questions/2169497頭類似的問題/ unexpected-class-getmethod-behavior並且沒有辦法繞着所有參數進行迭代並調用isAssignableFrom – Daff 2010-06-21 10:30:45

回答

8

reflection tutorial

建議使用Class.isAssignableFrom()樣品尋找print(String)

Method[] allMethods = c.getDeclaredMethods(); 
    for (Method m : allMethods) { 
     String mname = m.getName(); 
     if (!mname.startsWith("print") { 
      continue; 
     } 
     Type[] pType = m.getGenericParameterTypes(); 
     if ((pType.length != 1) 
      || !String.class.isAssignableFrom(pType[0].getClass())) { 
      continue; 
     } 
    } 
1

最簡單的方式做,這是通過java.beans.Statement中或java.beans.Expression。爲你做所有這些艱難的場地嗎?

getMethod()顯然不知道 一個字符串可以被輸送到一個方法 一個期望的對象

「不瞭解」是把它一個奇怪的方式。 getMethod()符合其規範。你必須提供形式參數,而不是實際參數的類型。

1

僅供參考,這是我如何調用方法使用反射與參數沒有提供其類型。

public class MyMethodUtils { 
    /** 
    * Need to pass parameter classes 
    */ 
    public static Object invoke(Object invoker, String methodName, Object[] parameters, Class[] parameterClasses) throws Exception { 
     Method method = invoker.getClass().getMethod(methodName, parameterClasses); 
     Object returnValue = method.invoke(invoker, parameters); 
     return returnValue; 
    } 

    /** 
    * No need to pass parameter classes 
    */ 
    public static Object invoke(Object invoker, String methodName, Object[] parameters) throws Exception { 
     Method[] allMethods = invoker.getClass().getDeclaredMethods(); 
     Object returnValue = null; 
     boolean isFound = false; 
     for (Method m : allMethods) { 
      String mname = m.getName(); 
      if (!mname.equals(methodName)) { 
       continue; 
      } 
      Class[] methodParaClasses = m.getParameterTypes(); 
      for (int i = 0; i < methodParaClasses.length; i++) { 
       Class<?> parameterClass = parameters[i].getClass(); 
       Class<?> methodParaClass = methodParaClasses[i]; 
       boolean isAssignable = methodParaClass.isAssignableFrom(parameterClass); 
       if (!isAssignable) { 
        continue; 
       } 
      } 
      returnValue = m.invoke(invoker, parameters); 
      isFound = true; 
     } 
     if (!isFound) { 
      throw new RuntimeException("Cannot find such method"); 
     } 

     return returnValue; 
    } 

} 

用法示例:

MyMethodUtils.invoke(student, "setNameAndMarks", new Object[] { "John", marks }, new Class[] { String.class, Collection.class }); 
    MyMethodUtils.invoke(student, "setNameAndMarks", new Object[] { "John", marks }); 

然而,該方法invoke(Object invoker, String methodName, Object[] parameters),可以調用錯誤的方法,如果簽名是模糊的。例如,如果存在用於調用兩種方法:

public void setNameAndMarks(String name, Collection<Integer> marks); 
public void setNameAndMarks(String name, ArrayList<Integer> marks); 

傳遞以下參數可以調用錯誤的方法

setNameAndMarks("John", new ArrayList<Integer>());