使用java.lang.reflect.getMethod和多态方法

时间:2010-06-21 10:17:55

标签: java reflection polymorphism

请考虑以下代码段:

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 个答案:

答案 0 :(得分: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 :(得分:1)

执行此操作的简单方法是通过java.beans.Statement或java.beans.Expression。是否所有这些硬码都适合你。

  

getMethod()显然没有意识到这一点   字符串可以被提供给方法   期待一个对象

'Unaware'是一种奇怪的方式。 getMethod()遵守其规范。您必须提供形式参数,而不是实际参数的类型。

答案 2 :(得分: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>());