2010-06-21 4 views
8

Betrachten Sie das folgende Snippet:Mit java.lang.reflect.getMethod mit polymorphen Methoden

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() ist offensichtlich nicht bewusst, dass ein String ein Verfahren zugeführt werden könnte, die eine Object (in der Tat erwartet, dann ist es Dokumentation sagt, dass es sucht nach Methode mit dem angegebenen Namen und genau die gleichen formalen Parametertypen).

Gibt es eine einfache Möglichkeit, Methoden reflexiv zu finden, wie getMethod() tut, aber Polymorphismus berücksichtigt, so dass die obige Reflexions Beispiel die print(Object) Methode, wenn sie mit ("print", String.class) Parameter abgefragt finden konnten?

+1

I ein ähnliches Problem in http://stackoverflow.com/questions/2169497 Kopf/unexpected-class-getmethod-behavior und es gab keine Möglichkeit, es mit der Iteration über alle Argumente und dem Aufruf von isAssignableFrom zu tun – Daff

Antwort

8

Die reflection tutorial

schlagen die Verwendung von Class.isAssignableFrom() Probe 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

Der einfache Weg über java.beans.Statement oder java.beans.Expression dies zu tun für die Suche. Macht all diese harten Werften für Sie.

getMethod() ist offensichtlich nicht bewusst, dass ein String ein Verfahren zugeführt werden könnte die

‚Ahnungslos‘ ein Objekt erwartet ist eine seltsame Weise zu setzen. getMethod() entspricht seiner Spezifikation. Sie müssen die formalen Parameter angeben, nicht die Typen der tatsächlichen Argumente.

1

FYI, es ist, wie ich Methode mit Reflektion mit mehrere Parameter aufrufen, ohne ihre Typen zu geben.

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

} 

Probe Verbrauch:

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

jedoch für das Verfahren invoke(Object invoker, String methodName, Object[] parameters) ist es möglich, falsche Methode aufzurufen, wenn die Signatur nicht eindeutig ist. Wenn beispielsweise gibt es zwei Methoden für den Aufrufer:

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

den folgenden Parameter Passing

falsche Methode aufrufen kann
setNameAndMarks("John", new ArrayList<Integer>()); 
Verwandte Themen