代码之家  ›  专栏  ›  技术社区  ›  Joonas Pulakka

将java.lang.reflect.getMethod与多态方法结合使用

  •  8
  • Joonas Pulakka  · 技术社区  · 14 年前

    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(Object) 方法查询时使用 ("print", String.class) 参数?

    3 回复  |  直到 14 年前
        1
  •  8
  •   stacker    14 年前

    这个 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;
            }
         }
    
        2
  •  1
  •   user207421    10 年前

    简单的方法是通过java.beans.Statement或java.beans.Expression。把这些硬码都给你了。

    getMethod()显然不知道 可以将字符串提供给方法

    “不知道”是一个奇怪的说法。 getMethod() 符合其规格。必须提供形式参数,而不是实际参数的类型。

        3
  •  1
  •   Michael W.    9 年前

    倍数 参数而不提供其类型。

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