2010-06-21 25 views
8

Hãy xem xét đoạn mã sau:Sử dụng java.lang.reflect.getMethod với các phương pháp đa hình

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() rõ ràng là không biết rằng một String có thể làm thức ăn cho một phương pháp mà hy vọng một Object (trên thực tế, đó là tài liệu nói rằng nó tìm kiếm phương thức với tên được chỉ định và chính xác các loại thông số chính thức giống nhau). Có một cách đơn giản để tìm phương pháp phản xạ, chẳng hạn như getMethod(), nhưng lấy tính đa hình vào tài khoản, sao cho ví dụ phản chiếu ở trên có thể tìm thấy phương pháp print(Object) khi được truy vấn với thông số ("print", String.class)?

+1

tôi lãnh đạo một vấn đề tương tự trong http://stackoverflow.com/questions/2169497/bất ngờ-class-getmethod-hành vi và không có một cách xung quanh làm nó với iterating trên tất cả các đối số và gọi làAssignableTừ – Daff

Trả lời

8

Các reflection tutorial

đề nghị việc sử dụng Class.isAssignableFrom() mẫu cho việc tìm kiếm 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

Cách đơn giản để làm điều này là thông qua java.beans.Statement hoặc java.beans.Expression. Liệu tất cả những cái sân cứng này dành cho bạn.

GetMethod() là rõ ràng không biết rằng một String có thể làm thức ăn cho một phương pháp rằng hy vọng một Object

'Không biết' là một cách kỳ lạ để đặt nó. getMethod() tuân theo đặc điểm kỹ thuật của nó. Bạn phải cung cấp các tham số chính thức, không phải là các kiểu đối số thực tế.

1

FYI, đó là cách tôi gọi phương thức bằng cách sử dụng phản chiếu với các tham số nhiều không cung cấp loại của chúng.

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

} 

Sample Cách sử dụng:

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

Tuy nhiên, đối với phương pháp invoke(Object invoker, String methodName, Object[] parameters), người ta có thể gọi phương thức sai nếu chữ ký là mơ hồ. Ví dụ, nếu có hai phương pháp cho Invoker:

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

Đi qua các tham số sau đây có thể gọi phương thức sai

setNameAndMarks("John", new ArrayList<Integer>()); 
Các vấn đề liên quan